diff --git a/background/background.go b/background/background.go index b800ac83..6afdabb4 100644 --- a/background/background.go +++ b/background/background.go @@ -3,6 +3,8 @@ package background import ( "context" "sync" + + "github.com/Gleipnir-Technology/nidus-sync/comms/email" ) var waitGroup sync.WaitGroup @@ -10,9 +12,9 @@ var waitGroup sync.WaitGroup func Start(ctx context.Context) { newOAuthTokenChannel = make(chan struct{}, 10) - channelJobAudio = make(chan jobAudio, 100) // Buffered channel to prevent blocking - channelJobEmail = make(chan jobEmail, 100) // Buffered channel to prevent blocking - channelJobText = make(chan jobText, 100) // Buffered channel to prevent blocking + channelJobAudio = make(chan jobAudio, 100) // Buffered channel to prevent blocking + channelJobEmail = make(chan email.Job, 100) // Buffered channel to prevent blocking + channelJobText = make(chan jobText, 100) // Buffered channel to prevent blocking waitGroup.Add(1) go func() { diff --git a/background/email.go b/background/email.go new file mode 100644 index 00000000..ea05ac9f --- /dev/null +++ b/background/email.go @@ -0,0 +1,42 @@ +package background + +import ( + "context" + + "github.com/Gleipnir-Technology/nidus-sync/comms/email" + "github.com/rs/zerolog/log" +) + +var channelJobEmail chan email.Job + +func ReportSubscriptionConfirmationEmail(destination, report_id string) { + enqueueJobEmail(email.NewJobReportSubscriptionConfirmation( + destination, + report_id, + )) +} + +func enqueueJobEmail(job email.Job) { + select { + case channelJobEmail <- job: + return + default: + log.Warn().Msg("email job channel is full, dropping job") + } +} + +func startWorkerEmail(ctx context.Context, channel chan email.Job) { + go func() { + for { + select { + case <-ctx.Done(): + log.Info().Msg("Email worker shutting down.") + return + case job := <-channel: + err := email.Handle(ctx, job) + if err != nil { + } + } + } + }() +} diff --git a/background/comms.go b/background/text.go similarity index 57% rename from background/comms.go rename to background/text.go index b33de091..853f7041 100644 --- a/background/comms.go +++ b/background/text.go @@ -11,17 +11,8 @@ import ( "github.com/rs/zerolog/log" ) -var channelJobEmail chan jobEmail var channelJobText chan jobText -func ReportSubscriptionConfirmationEmail(destination string) { - enqueueJobEmail(jobEmail{ - Destination: destination, - Source: config.ForwardEmailReportAddress, - Type: enums.CommsMessagetypeemailReportSubscriptionConfirmation, - }) -} - func ReportSubscriptionConfirmationText(destination comms.E164, report_id string) { enqueueJobText(jobText{ Destination: destination, @@ -31,12 +22,6 @@ func ReportSubscriptionConfirmationText(destination comms.E164, report_id string }) } -type jobEmail struct { - Destination string - ReportID string - Source string - Type enums.CommsMessagetypeemail -} type jobText struct { Destination comms.E164 ReportID string @@ -44,15 +29,6 @@ type jobText struct { Type enums.CommsMessagetypetext } -func enqueueJobEmail(job jobEmail) { - select { - case channelJobEmail <- job: - log.Info().Str("destination", job.Destination).Msg("Enqueued email job") - default: - log.Warn().Msg("email job channel is full, dropping job") - } -} - func enqueueJobText(job jobText) { select { case channelJobText <- job: @@ -62,23 +38,6 @@ func enqueueJobText(job jobText) { } } -func startWorkerEmail(ctx context.Context, channel chan jobEmail) { - go func() { - for { - select { - case <-ctx.Done(): - log.Info().Msg("Email worker shutting down.") - return - case job := <-channel: - err := jobProcessEmail(ctx, job) - if err != nil { - log.Error().Err(err).Str("dest", job.Destination).Str("type", string(job.Type)).Msg("Error processing email") - } - } - } - }() -} - func startWorkerText(ctx context.Context, channel chan jobText) { go func() { for { @@ -96,22 +55,6 @@ func startWorkerText(ctx context.Context, channel chan jobText) { }() } -func jobProcessEmail(ctx context.Context, job jobEmail) error { - switch job.Type { - case enums.CommsMessagetypeemailInitialContact: - return comms.SendEmailInitialContact(ctx, job.Destination) - default: - return errors.New("not implemented") - } - /* - case enums.CommsMessagetypeemailReportSubscriptionConfirmation: - case enums.CommsMessagetypeemailReportStatusScheduled: - case enums.CommsMessagetypeemailReportStatusComplete: - - } - */ -} - func jobProcessText(job jobText) error { var message string switch job.Type { diff --git a/comms/email.go b/comms/email.go deleted file mode 100644 index 56a34844..00000000 --- a/comms/email.go +++ /dev/null @@ -1,245 +0,0 @@ -package comms - -import ( - "bytes" - "context" - "embed" - "encoding/json" - "fmt" - "io" - "net/http" - "time" - - "github.com/Gleipnir-Technology/nidus-sync/config" - "github.com/Gleipnir-Technology/nidus-sync/db" - "github.com/Gleipnir-Technology/nidus-sync/db/enums" - "github.com/Gleipnir-Technology/nidus-sync/db/models" - "github.com/Gleipnir-Technology/nidus-sync/htmlpage" - "github.com/aarondl/opt/omit" - "github.com/rs/zerolog/log" -) - -func RenderEmailInitial(w http.ResponseWriter, destination string) { - content := newContentEmailInitial(destination) - renderOrError(w, initialT, content) -} - -func RenderEmailReportConfirmation(w http.ResponseWriter, report_id string) { - content := newContentEmailSubscriptionConfirmation(report_id) - renderOrError(w, reportConfirmationT, content) -} - -func SendEmailInitialContact(ctx context.Context, destination string) error { - content := newContentEmailInitial(destination) - text, html, err := renderEmailTemplates(reportConfirmationT, content) - if err != nil { - return fmt.Errorf("Failed to render email temlate: %w", err) - } - resp, err := sendEmail(ctx, emailRequest{ - From: config.ForwardEmailReportAddress, - HTML: html, - Subject: "Welcome", - Text: text, - To: destination, - }, enums.CommsMessagetypeemailInitialContact) - if err != nil { - return fmt.Errorf("Failed to send email to %s: %w", err) - } - log.Info().Str("id", resp.ID).Str("to", destination).Msg("Sent initial contact email") - return nil -} - -func SendEmailReportConfirmation(ctx context.Context, to string, report_id string) error { - report_id_str := publicReportID(report_id) - content := newContentEmailSubscriptionConfirmation(report_id) - text, html, err := renderEmailTemplates(reportConfirmationT, content) - if err != nil { - return fmt.Errorf("Failed to render template %s: %w", reportConfirmationT.name, err) - } - resp, err := sendEmail(ctx, emailRequest{ - From: config.ForwardEmailReportAddress, - HTML: html, - Subject: fmt.Sprintf("Mosquito Report Submission - %s", report_id_str), - Text: text, - To: to, - }, enums.CommsMessagetypeemailReportSubscriptionConfirmation) - if err != nil { - return fmt.Errorf("Failed to send email report confirmation to %s for report %s: %w", to, report_id, err) - } - log.Info().Str("id", resp.ID).Str("to", to).Str("report_id", report_id).Msg("Sent report confirmation email") - return nil -} - -var ( - initialT = buildTemplate("initial") - reportConfirmationT = buildTemplate("report-subscription-confirmation") -) - -//go:embed template/* -var embeddedFiles embed.FS - -type attachmentRequest struct { - Filename string `json:"filename"` - Content string `json:"content"` -} - -type contentEmailBase struct { - URLLogo string - URLUnsubscribe string - URLViewInBrowser string -} - -type contentEmailReportConfirmation struct { - Base contentEmailBase - URLReportStatus string -} -type contentEmailInitial struct { - Base contentEmailBase - Destination string - URLSubscribe string -} - -type emailRequest struct { - From string `json:"from"` - To string `json:"to"` - CC []string `json:"cc,omitempty"` - BCC []string `json:"bcc,omitempty"` - Subject string `json:"subject"` - Text string `json:"text"` - HTML string `json:"html,omitempty"` - Attachments []attachmentRequest `json:"attachments,omitempty"` - Sender string `json:"sender"` - ReplyTo string `json:"replyTo,omitempty"` - InReplyTo string `json:"inReplyTo,omitempty"` - References []string `json:"references,omitempty"` -} - -type emailEnvelope struct { - From string `json:"from"` - To []string `json:"to"` -} - -type emailResponse struct { - IsRedacted bool `json:"is_redacted"` - CreatedAt string `json:"created_at"` - HardBounces []string `json:"hard_bounces"` - SoftBounces []string `json:"soft_bounces"` - IsBounce bool `json:"is_bounce"` - Alias string `json:"alias"` - Domain string `json:"domain"` - User string `json:"user"` - Status string `json:"status"` - IsLocked bool `json:"is_locked"` - Envelope emailEnvelope `json:"envelope"` - RequireTLS bool `json:"requireTLS"` - MessageID string `json:"messageId"` - Headers map[string]string `json:"headers"` - Date string `json:"date"` - Subject string `json:"subject"` - Accepted []string `json:"accepted"` - Deliveries []string `json:"deliveries"` - RejectedErrors []string `json:"rejectedErrors"` - ID string `json:"id"` - Object string `json:"object"` - UpdatedAt string `json:"updated_at"` - Link string `json:"link"` - Message string `json:"message"` -} - -func newContentBase(b *contentEmailBase, url string) { - b.URLLogo = config.MakeURLReport("/static/img/nidus-logo-no-lettering-64.png") - b.URLUnsubscribe = config.MakeURLReport("/email/unsubscribe") - b.URLViewInBrowser = url -} - -func newContentEmailInitial(destination string) (result contentEmailInitial) { - newContentBase( - &result.Base, - config.MakeURLReport("/email/initial"), - ) - result.Destination = destination - result.URLSubscribe = config.MakeURLReport("/email/subscribe?email=%s", destination) - return result -} -func newContentEmailSubscriptionConfirmation(report_id string) (result contentEmailReportConfirmation) { - newContentBase( - &result.Base, - config.MakeURLReport("/email/report/%s/subscription-confirmation", report_id), - ) - result.URLReportStatus = config.MakeURLReport("/status/%s", report_id) - return result -} - -func publicReportID(s string) string { - if len(s) != 12 { - return s - } - return s[0:4] + "-" + s[4:8] + "-" + s[8:12] -} - -func renderOrError(w http.ResponseWriter, template *builtTemplate, context interface{}) { - buf := &bytes.Buffer{} - err := template.executeTemplateHTML(buf, context) - if err != nil { - log.Error().Err(err).Str("name", template.name).Msg("Failed to render template") - htmlpage.RespondError(w, "Failed to render template", err, http.StatusInternalServerError) - return - } - buf.WriteTo(w) -} - -var FORWARDEMAIL_API = "https://api.forwardemail.net/v1/emails" - -func ensureInDB(ctx context.Context, destination string) (err error) { - _, err = models.FindCommsEmail(ctx, db.PGInstance.BobDB, destination) - if err != nil { - // assume it exists - log.Warn().Err(err).Msg("ElI, check what this error should look like") - return nil - } - _, err = models.CommsEmails.Insert(&models.CommsEmailSetter{ - Address: omit.From(destination), - Confirmed: omit.From(false), - IsSubscribed: omit.From(false), - }).One(ctx, db.PGInstance.BobDB) - if err != nil { - return fmt.Errorf("Failed to insert new email: %w", err) - } - log.Info().Str("email", destination).Msg("Added email to the comms database") - return nil -} - -func insertEmailLog(ctx context.Context, email emailRequest, t enums.CommsMessagetypeemail) (err error) { - _, err = models.CommsEmailLogs.Insert(&models.CommsEmailLogSetter{ - Created: omit.From(time.Now()), - Destination: omit.From(email.To), - Source: omit.From(email.From), - Type: omit.From(t), - }).One(ctx, db.PGInstance.BobDB) - return err -} -func sendEmail(ctx context.Context, email emailRequest, t enums.CommsMessagetypeemail) (response emailResponse, err error) { - ensureInDB(ctx, email.To) - payload, err := json.Marshal(email) - if err != nil { - return response, fmt.Errorf("Failed to marshal email request: %w", err) - } - - insertEmailLog(ctx, email, t) - req, _ := http.NewRequest("POST", FORWARDEMAIL_API, bytes.NewReader(payload)) - req.SetBasicAuth(config.ForwardEmailAPIToken, "") - req.Header.Add("Content-Type", "application/json") - - res, _ := http.DefaultClient.Do(req) - - defer res.Body.Close() - body, _ := io.ReadAll(res.Body) - - // Parse the JSON response - err = json.Unmarshal(body, &response) - if err != nil { - log.Warn().Str("status", res.Status).Str("response_body", string(body)).Msg("Attempted to send email but couldn't parse the resulting JSON") - return response, fmt.Errorf("Failed to unmarshal JSON response: %w", err) - } - return response, nil -} diff --git a/comms/email/db.go b/comms/email/db.go new file mode 100644 index 00000000..39d4dc59 --- /dev/null +++ b/comms/email/db.go @@ -0,0 +1,103 @@ +package email + +import ( + "context" + "crypto/sha256" + "database/sql" + "encoding/hex" + "fmt" + "sort" + "strings" + "time" + + "github.com/Gleipnir-Technology/nidus-sync/db" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/rs/zerolog/log" + "github.com/stephenafamo/bob/types/pgtypes" +) + +func convertToPGData(data map[string]string) pgtypes.HStore { + result := pgtypes.HStore{} + for k, v := range data { + result[k] = sql.Null[string]{V: v, Valid: true} + } + return result +} + +func ensureInDB(ctx context.Context, destination string) (err error) { + _, err = models.FindCommsEmailContact(ctx, db.PGInstance.BobDB, destination) + if err != nil { + // doesn't exist + if err.Error() == "sql: no rows in result set" { + public_id := fmt.Sprintf("%x", sha256.Sum256([]byte(destination))) + _, err = models.CommsEmailContacts.Insert(&models.CommsEmailContactSetter{ + Address: omit.From(destination), + Confirmed: omit.From(false), + IsSubscribed: omit.From(false), + PublicID: omit.From(public_id), + }).One(ctx, db.PGInstance.BobDB) + if err != nil { + return fmt.Errorf("Failed to insert new email: %w", err) + } + log.Info().Str("email", destination).Msg("Added email to the comms database") + return nil + } + return fmt.Errorf("Unexpected error searching for contact: %w", err) + } + return nil +} + +func insertEmailLog(ctx context.Context, data map[string]string, destination string, public_id string, source string, subject string, template_id int32) (err error) { + data_for_insert := convertToPGData(data) + _, err = models.CommsEmailLogs.Insert(&models.CommsEmailLogSetter{ + //ID: + Created: omit.From(time.Now()), + DeliveryStatus: omit.From("initial"), + Destination: omit.From(destination), + PublicID: omit.From(public_id), + SentAt: omitnull.FromPtr[time.Time](nil), + Source: omit.From(source), + Subject: omit.From(subject), + TemplateID: omitnull.From(templateInitialID), + TemplateData: omit.From(data_for_insert), + Type: omit.From(enums.CommsMessagetypeemailInitialContact), + }).One(ctx, db.PGInstance.BobDB) + + return err +} +func generatePublicId(t enums.CommsMessagetypeemail, m map[string]string) string { + if m == nil || len(m) == 0 { + // Return hash of empty string for empty maps + emptyHash := sha256.Sum256([]byte("")) + return hex.EncodeToString(emptyHash[:]) + } + + // Get and sort keys for deterministic ordering + keys := make([]string, 0, len(m)) + for k := range m { + keys = append(keys, k) + } + sort.Strings(keys) + + // Build a string with all key-value pairs + var sb strings.Builder + // Add type first + sb.WriteString(fmt.Sprintf("type:%s,", t)) + for _, k := range keys { + sb.WriteString(k) + sb.WriteString(":") // Separator between key and value + sb.WriteString(m[k]) + sb.WriteString(",") // Separator between pairs + } + + // Compute SHA-256 hash + hasher := sha256.New() + hasher.Write([]byte(sb.String())) + hashBytes := hasher.Sum(nil) + + // Convert to hex string and return + return hex.EncodeToString(hashBytes) +} diff --git a/comms/email/email.go b/comms/email/email.go new file mode 100644 index 00000000..ed33d08d --- /dev/null +++ b/comms/email/email.go @@ -0,0 +1,108 @@ +package email + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + + "github.com/Gleipnir-Technology/nidus-sync/config" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/rs/zerolog/log" +) + +type attachmentRequest struct { + Filename string `json:"filename"` + Content string `json:"content"` +} + +type contentEmailBase struct { + URLLogo string + URLUnsubscribe string + URLViewInBrowser string +} + +type contentEmailReportConfirmation struct { + Base contentEmailBase + URLReportStatus string +} +type contentEmailInitial struct { + Base contentEmailBase + Destination string + URLSubscribe string +} + +type emailRequest struct { + From string `json:"from"` + To string `json:"to"` + CC []string `json:"cc,omitempty"` + BCC []string `json:"bcc,omitempty"` + Subject string `json:"subject"` + Text string `json:"text"` + HTML string `json:"html,omitempty"` + Attachments []attachmentRequest `json:"attachments,omitempty"` + Sender string `json:"sender"` + ReplyTo string `json:"replyTo,omitempty"` + InReplyTo string `json:"inReplyTo,omitempty"` + References []string `json:"references,omitempty"` +} + +type emailEnvelope struct { + From string `json:"from"` + To []string `json:"to"` +} + +type emailResponse struct { + IsRedacted bool `json:"is_redacted"` + CreatedAt string `json:"created_at"` + HardBounces []string `json:"hard_bounces"` + SoftBounces []string `json:"soft_bounces"` + IsBounce bool `json:"is_bounce"` + Alias string `json:"alias"` + Domain string `json:"domain"` + User string `json:"user"` + Status string `json:"status"` + IsLocked bool `json:"is_locked"` + Envelope emailEnvelope `json:"envelope"` + RequireTLS bool `json:"requireTLS"` + MessageID string `json:"messageId"` + Headers map[string]string `json:"headers"` + Date string `json:"date"` + Subject string `json:"subject"` + Accepted []string `json:"accepted"` + Deliveries []string `json:"deliveries"` + RejectedErrors []string `json:"rejectedErrors"` + ID string `json:"id"` + Object string `json:"object"` + UpdatedAt string `json:"updated_at"` + Link string `json:"link"` + Message string `json:"message"` +} + +var FORWARDEMAIL_API = "https://api.forwardemail.net/v1/emails" + +func sendEmail(ctx context.Context, email emailRequest, t enums.CommsMessagetypeemail) (response emailResponse, err error) { + payload, err := json.Marshal(email) + if err != nil { + return response, fmt.Errorf("Failed to marshal email request: %w", err) + } + + req, _ := http.NewRequest("POST", FORWARDEMAIL_API, bytes.NewReader(payload)) + req.SetBasicAuth(config.ForwardEmailAPIToken, "") + req.Header.Add("Content-Type", "application/json") + + res, _ := http.DefaultClient.Do(req) + + defer res.Body.Close() + body, _ := io.ReadAll(res.Body) + + // Parse the JSON response + err = json.Unmarshal(body, &response) + if err != nil { + log.Warn().Str("status", res.Status).Str("response_body", string(body)).Msg("Attempted to send email but couldn't parse the resulting JSON") + return response, fmt.Errorf("Failed to unmarshal JSON response: %w", err) + } + return response, nil +} diff --git a/comms/email/initial.go b/comms/email/initial.go new file mode 100644 index 00000000..fd42fa1d --- /dev/null +++ b/comms/email/initial.go @@ -0,0 +1,74 @@ +package email + +import ( + "context" + "fmt" + + "github.com/Gleipnir-Technology/nidus-sync/config" + "github.com/Gleipnir-Technology/nidus-sync/db" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/rs/zerolog/log" +) + +type jobInitial struct { + base jobEmailBase +} + +func (job jobInitial) Destination() string { + return job.base.destination +} + +func maybeSendInitialEmail(ctx context.Context, destination string) error { + err := ensureInDB(ctx, destination) + if err != nil { + return fmt.Errorf("Failed to add email recipient to database: %w", err) + } + rows, err := models.CommsEmailLogs.Query( + models.SelectWhere.CommsEmailLogs.Destination.EQ(destination), + models.SelectWhere.CommsEmailLogs.TemplateID.EQ(templateInitialID), + ).All(ctx, db.PGInstance.BobDB) + + // We already sent an initial email + if len(rows) > 0 { + return nil + } + + return sendEmailInitialContact(ctx, destination) +} +func sendEmailInitialContact(ctx context.Context, destination string) error { + //data := pgtypes.HStore{} + data := make(map[string]string, 0) + source := config.ForwardEmailReportAddress + data["destination"] = destination + data["source"] = source + data["url_logo"] = config.MakeURLReport("/static/img/nidus-logo-no-lettering-64.png") + data["url_subscribe"] = config.MakeURLReport("/email/subscribe?email=%s", destination) + data["url_unsubscribe"] = config.MakeURLReport("/email/unsubscribe") + public_id := generatePublicId(enums.CommsMessagetypeemailInitialContact, data) + data["url_browser"] = config.MakeURLReport("/email?id=%s", public_id) + + text, html, err := renderEmailTemplates(templateInitialID, data) + if err != nil { + return fmt.Errorf("Failed to render email temlates: %w", err) + } + + subject := "Welcome" + err = insertEmailLog(ctx, data, destination, public_id, source, subject, templateInitialID) + if err != nil { + return fmt.Errorf("Failed to store email log: %w", err) + } + resp, err := sendEmail(ctx, emailRequest{ + From: source, + HTML: html, + Subject: subject, + Text: text, + To: destination, + }, enums.CommsMessagetypeemailInitialContact) + + if err != nil { + return fmt.Errorf("Failed to send email to %s: %w", err) + } + log.Info().Str("id", resp.ID).Str("to", destination).Msg("Sent initial contact email") + return nil +} diff --git a/comms/email/job.go b/comms/email/job.go new file mode 100644 index 00000000..b2f3fec7 --- /dev/null +++ b/comms/email/job.go @@ -0,0 +1,44 @@ +package email + +import ( + "context" + "errors" + "fmt" + + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/rs/zerolog/log" +) + +type Job interface { + destination() string + messageType() enums.CommsMessagetypeemail + renderHTML() (string, error) + renderTXT() (string, error) + subject() string +} + +type jobEmailBase struct { + destination string + source string +} + +func Handle(ctx context.Context, job Job) error { + var err error + switch job.messageType() { + case enums.CommsMessagetypeemailReportSubscriptionConfirmation: + err = sendEmailReportConfirmation(ctx, job) + default: + return errors.New("not implemented") + } + if err != nil { + log.Error().Err(err).Str("dest", job.destination()).Str("type", string(job.messageType())).Msg("Error processing email") + return fmt.Errorf("Failed to handle email: %w", err) + } + return nil + /* + case enums.CommsMessagetypeemailReportStatusScheduled: + case enums.CommsMessagetypeemailReportStatusComplete: + + } + */ +} diff --git a/comms/email/report_subscription_confirmation.go b/comms/email/report_subscription_confirmation.go new file mode 100644 index 00000000..c689859d --- /dev/null +++ b/comms/email/report_subscription_confirmation.go @@ -0,0 +1,80 @@ +package email + +import ( + "context" + "fmt" + + "github.com/Gleipnir-Technology/nidus-sync/config" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + //"github.com/rs/zerolog/log" +) + +func NewJobReportSubscriptionConfirmation(destination, report_id string) Job { + return jobEmailReportSubscriptionConfirmation{ + dest: destination, + reportID: report_id, + } +} + +type jobEmailReportSubscriptionConfirmation struct { + dest string + reportID string +} + +func (job jobEmailReportSubscriptionConfirmation) destination() string { + return job.dest +} +func (job jobEmailReportSubscriptionConfirmation) messageType() enums.CommsMessagetypeemail { + return enums.CommsMessagetypeemailReportSubscriptionConfirmation +} +func (job jobEmailReportSubscriptionConfirmation) renderHTML() (string, error) { + _ = newContentEmailSubscriptionConfirmation(job) + return "", nil +} +func (job jobEmailReportSubscriptionConfirmation) renderTXT() (string, error) { + return "fake txt", nil +} +func (job jobEmailReportSubscriptionConfirmation) subject() string { + return "" +} + +func sendEmailReportConfirmation(ctx context.Context, job Job) error { + j, ok := job.(jobEmailReportSubscriptionConfirmation) + if !ok { + return fmt.Errorf("job is not for report subscription confirmation") + } + err := maybeSendInitialEmail(ctx, j.destination()) + if err != nil { + return fmt.Errorf("Failed to handle initial email: %w", err) + } + return nil + /* + report_id_str := publicReportID(report_id) + content := newContentEmailSubscriptionConfirmation(report_id) + text, html, err := renderEmailTemplates(reportConfirmationT, content) + if err != nil { + return fmt.Errorf("Failed to render template %s: %w", reportConfirmationT.name, err) + } + resp, err := sendEmail(ctx, emailRequest{ + From: config.ForwardEmailReportAddress, + HTML: html, + Subject: fmt.Sprintf("Mosquito Report Submission - %s", report_id_str), + Text: text, + To: to, + }, enums.CommsMessagetypeemailReportSubscriptionConfirmation) + if err != nil { + return fmt.Errorf("Failed to send email report confirmation to %s for report %s: %w", to, report_id, err) + } + log.Info().Str("id", resp.ID).Str("to", to).Str("report_id", report_id).Msg("Sent report confirmation email") + return nil + */ +} + +func newContentEmailSubscriptionConfirmation(job jobEmailReportSubscriptionConfirmation) (result contentEmailReportConfirmation) { + /*newContentBase( + &result.Base, + config.MakeURLReport("/email/report/%s/subscription-confirmation", job.reportID), + )*/ + result.URLReportStatus = config.MakeURLReport("/status/%s", job.reportID) + return result +} diff --git a/comms/email/template.go b/comms/email/template.go new file mode 100644 index 00000000..424619f6 --- /dev/null +++ b/comms/email/template.go @@ -0,0 +1,319 @@ +package email + +import ( + "bytes" + "context" + "crypto/sha256" + "embed" + "errors" + "fmt" + templatehtml "html/template" + "io" + "io/fs" + "path" + "path/filepath" + "strings" + templatetxt "text/template" + "time" + + "github.com/Gleipnir-Technology/nidus-sync/db" + "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/rs/zerolog/log" + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + "github.com/stephenafamo/bob/dialect/psql/um" +) + +//go:embed template/* +var embeddedFiles embed.FS + +var ( + templateByID map[int32]*builtTemplate + templateInitialID int32 +) + +type templatePair struct { + baseName string + messageType enums.CommsMessagetypeemail + htmlContent string + txtContent string + htmlHash string + txtHash string +} + +func LoadTemplates() error { + all_templates, err := readTemplates(embeddedFiles) + if err != nil { + return fmt.Errorf("Failed to read templates: %w", err) + } + ctx := context.TODO() + tx, err := db.PGInstance.BobDB.BeginTx(ctx, nil) + if err != nil { + return fmt.Errorf("Failed to start transaction: %w", err) + } + defer tx.Rollback(ctx) + templateByID = make(map[int32]*builtTemplate, 0) + for name, p := range all_templates { + template_id, err := templateDBID(tx, name, p) + if err != nil { + return fmt.Errorf("Failed to add '%s' to DB: %w", name, err) + } + template_html, err := templatehtml.New(name).Parse(p.htmlContent) + if err != nil { + return fmt.Errorf("Failed to parse HTML portion of '%s': %w", name, err) + } + template_txt, err := templatetxt.New(name).Parse(p.txtContent) + if err != nil { + return fmt.Errorf("Failed to parse HTML portion of '%s': %w", name, err) + } + built := builtTemplate{ + name: name, + templateHTML: template_html, + templateTXT: template_txt, + } + templateByID[template_id] = &built + log.Info().Int32("id", template_id).Str("name", name).Msg("Added template to cache") + } + templateInitialID, err = loadTemplateID(ctx, tx, enums.CommsMessagetypeemailInitialContact) + if err != nil { + return fmt.Errorf("Failed to load template ID: %s", err) + } + tx.Commit(ctx) + return nil +} + +func loadTemplateID(ctx context.Context, tx bob.Tx, t enums.CommsMessagetypeemail) (int32, error) { + templates, err := models.CommsEmailTemplates.Query( + models.SelectWhere.CommsEmailTemplates.MessageType.EQ(t), + models.SelectWhere.CommsEmailTemplates.Superceded.IsNull(), + ).All(ctx, tx) + if err != nil { + return 0, fmt.Errorf("Failed to query template '%s': %w", t, err) + } + switch len(templates) { + case 0: + return 0, fmt.Errorf("No matching templates for '%s", t) + case 1: + return templates[0].ID, nil + default: + return 0, fmt.Errorf("Found %d templates for '%s', should only have 1", len(templates), t) + } +} + +func readTemplates(filesystem embed.FS) (results map[string]*templatePair, err error) { + // First pass: read files and organize by base name + results = make(map[string]*templatePair) + + err = fs.WalkDir(filesystem, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + if d.IsDir() { + return nil + } + + // Read file content + content, err := filesystem.ReadFile(path) + if err != nil { + return fmt.Errorf("error reading template %s: %w", path, err) + } + + // Calculate hash + hash := fmt.Sprintf("%x", sha256.Sum256(content)) + + // Extract base name and extension + ext := strings.ToLower(filepath.Ext(path)) + baseName := strings.TrimSuffix(filepath.Base(path), ext) + + // Store in map by base name + if _, exists := results[baseName]; !exists { + t, err := messageTypeFromName(baseName) + if err != nil { + return fmt.Errorf("Cannot parse email templates: %w", err) + } + results[baseName] = &templatePair{ + baseName: baseName, + messageType: *t, + } + } + + // Add content based on extension + switch ext { + case ".html", ".htm": + results[baseName].htmlContent = string(content) + results[baseName].htmlHash = hash + case ".txt": + results[baseName].txtContent = string(content) + results[baseName].txtHash = hash + } + + return nil + }) + + if err != nil { + return results, fmt.Errorf("error walking template directory: %w", err) + } + + return results, nil +} + +func templateDBID(tx bob.Tx, name string, pair *templatePair) (int32, error) { + ctx := context.Background() + + // Skip incomplete pairs + if pair.htmlContent == "" { + return 0, fmt.Errorf("Bad template pair '%s': no html content") + } + if pair.txtContent == "" { + return 0, fmt.Errorf("Bad template pair '%s': no txt content") + } + + // Check if a template with these hashes already exists + rows, err := models.CommsEmailTemplates.Query( + models.SelectWhere.CommsEmailTemplates.ContentHashHTML.EQ(pair.htmlHash), + models.SelectWhere.CommsEmailTemplates.ContentHashTXT.EQ(pair.txtHash), + models.SelectWhere.CommsEmailTemplates.MessageType.EQ(pair.messageType), + ).All(ctx, tx) + if err != nil { + return 0, fmt.Errorf("Failed to query for existing template: %w", err) + } + if len(rows) > 1 { + return 0, fmt.Errorf("Got %d template rows, should only have 1", len(rows)) + } else if len(rows) == 1 { + return rows[0].ID, nil + } + + // Supercede previous templates of this type + _, err = psql.Update( + um.Table(models.CommsEmailTemplates.Alias()), + um.SetCol("superceded").ToArg(time.Now()), + //um.Where(models.CommsEmailTemplates.Columns.MessageType.EQ(psql.Arg(pair.messageType))), + um.Where(psql.Quote("message_type").EQ(psql.Arg(pair.messageType))), + //um.Where(models.CommsEmailTemplates.Columns.Superceded.IsNull()), + um.Where(psql.Quote("superceded").IsNull()), + ).Exec(ctx, tx) + if err != nil { + return 0, fmt.Errorf("error superceding templates: %w", err) + } + + new_template, err := models.CommsEmailTemplates.Insert(&models.CommsEmailTemplateSetter{ + ContentHTML: omit.From(pair.htmlContent), + ContentTXT: omit.From(pair.txtContent), + ContentHashHTML: omit.From(pair.htmlHash), + ContentHashTXT: omit.From(pair.txtHash), + Created: omit.From(time.Now()), + Superceded: omitnull.FromPtr[time.Time](nil), + MessageType: omit.From(pair.messageType), + }).One(ctx, tx) + if err != nil { + return 0, fmt.Errorf("Failed to insert new template: %w", err) + } + log.Info().Int32("id", new_template.ID).Str("type", string(pair.messageType)).Msg("Added new email template") + + return new_template.ID, nil +} + +type builtTemplate struct { + name string + templateHTML *templatehtml.Template + templateTXT *templatetxt.Template +} + +func (bt *builtTemplate) executeTemplateHTML(w io.Writer, content any) error { + if bt.templateHTML == nil { + file := templateFileHTML(bt.name) + templ, err := parseFromDiskHTML(file) + if err != nil { + return fmt.Errorf("Failed to parse template file: %w", err) + } + if templ == nil { + w.Write([]byte("Failed to read from disk: ")) + return errors.New("Template parsing failed") + } + //log.Debug().Str("name", templ.Name()).Msg("Parsed template") + return templ.ExecuteTemplate(w, bt.name, content) + } else { + return bt.templateHTML.ExecuteTemplate(w, bt.name, content) + } +} +func (bt *builtTemplate) executeTemplateTXT(w io.Writer, content any) error { + if bt.templateTXT == nil { + file := templateFileTXT(bt.name) + templ, err := parseFromDiskTXT(file) + if err != nil { + return fmt.Errorf("Failed to parse template file: %w", err) + } + if templ == nil { + w.Write([]byte("Failed to read from disk: ")) + return errors.New("Template parsing failed") + } + //log.Debug().Str("name", templ.Name()).Msg("Parsed template") + return templ.ExecuteTemplate(w, bt.name, content) + } else { + return bt.templateTXT.ExecuteTemplate(w, bt.name, content) + } +} +func templateFileHTML(name string) string { + return fmt.Sprintf("comms/template/%s.html", name) +} +func templateFileTXT(name string) string { + return fmt.Sprintf("comms/template/%s.txt", name) +} + +func messageTypeFromName(n string) (*enums.CommsMessagetypeemail, error) { + for _, t := range enums.AllCommsMessagetypeemail() { + if n == string(t) { + return &t, nil + } + } + return nil, fmt.Errorf("Unrecognized email type '%s'", n) +} + +func parseFromDiskHTML(file string) (*templatehtml.Template, error) { + name := path.Base(file) + //log.Debug().Str("name", name).Strs("files", files).Msg("parsing from disk") + templ, err := templatehtml.New(name).ParseFiles(file) + if err != nil { + return nil, fmt.Errorf("Failed to parse %s: %w", file, err) + } + return templ, nil +} + +func parseFromDiskTXT(file string) (*templatetxt.Template, error) { + name := path.Base(file) + //log.Debug().Str("name", name).Strs("files", files).Msg("parsing from disk") + templ, err := templatetxt.New(name).ParseFiles(file) + if err != nil { + return nil, fmt.Errorf("Failed to parse %s: %w", file, err) + } + return templ, nil +} + +func publicReportID(s string) string { + if len(s) != 12 { + return s + } + return s[0:4] + "-" + s[4:8] + "-" + s[8:12] +} + +func renderEmailTemplates(template_id int32, content map[string]string) (text string, html string, err error) { + buf_txt := &bytes.Buffer{} + t, ok := templateByID[template_id] + if !ok { + return "", "", fmt.Errorf("Failed to lookup template %d", template_id) + } + err = t.executeTemplateTXT(buf_txt, content) + if err != nil { + return "", "", fmt.Errorf("Failed to render TXT template: %w", err) + } + buf_html := &bytes.Buffer{} + err = t.executeTemplateHTML(buf_html, content) + if err != nil { + return "", "", fmt.Errorf("Failed to render HTML template: %w", err) + } + return buf_txt.String(), buf_html.String(), nil +} diff --git a/comms/template/initial.html b/comms/email/template/initial-contact.html similarity index 84% rename from comms/template/initial.html rename to comms/email/template/initial-contact.html index ef65f4ed..341e3ae4 100644 --- a/comms/template/initial.html +++ b/comms/email/template/initial-contact.html @@ -65,31 +65,31 @@
- Email not displaying correctly? View it in your browser + Email not displaying correctly? View it in your browser
- +

Welcome

-

We're sending you this email because it's the first time we've gotten this email address ({{.Destination}}).

+

We're sending you this email because it's the first time we've gotten this email address ({{.destination}}).

If you'd rather not receive emails from us you can reply with "Unsubscribe" in the subject or body of the email. You can also use the "Unsubscribe" feature of your mail client, if it supports list unsubscribes.

If instead you'd like to confirm that you're willing to receive emails at this address, you can do so by clicking below:

- I want emails from Report Mosquitoes Online + I want emails from Report Mosquitoes Online
diff --git a/comms/email/template/initial-contact.txt b/comms/email/template/initial-contact.txt new file mode 100644 index 00000000..92c358cd --- /dev/null +++ b/comms/email/template/initial-contact.txt @@ -0,0 +1,7 @@ +We're sending you this email because it's the first time we've gotten this email address ({{.Destination}}). +If you'd rather not receive emails from us you can reply with "Unsubscribe" in the subject or body of the email. You can also use the "Unsubscribe" feature of your mail client, if it supports list unsubscribes. +If instead you'd like to confirm that you're willing to receive emails at this address, you can do so by openining the following URL in a web browser: {{.URLSubscribe}}. You can also confirm your willingness by replying to this email with 'Confirm' in the subject on the body of the email. + +Thank you, +Report Mosquitoes Online + diff --git a/comms/template/report-subscription-confirmation.html b/comms/email/template/report-subscription-confirmation.html similarity index 100% rename from comms/template/report-subscription-confirmation.html rename to comms/email/template/report-subscription-confirmation.html diff --git a/comms/template/report-subscription-confirmation.txt b/comms/email/template/report-subscription-confirmation.txt similarity index 100% rename from comms/template/report-subscription-confirmation.txt rename to comms/email/template/report-subscription-confirmation.txt diff --git a/comms/template.go b/comms/template.go deleted file mode 100644 index 5eaa4d00..00000000 --- a/comms/template.go +++ /dev/null @@ -1,148 +0,0 @@ -package comms - -import ( - "bytes" - "embed" - "errors" - "fmt" - templatehtml "html/template" - "io" - "os" - "path" - "strings" - templatetxt "text/template" - - "github.com/Gleipnir-Technology/nidus-sync/config" - "github.com/rs/zerolog/log" -) - -type builtTemplate struct { - name string - templateHTML *templatehtml.Template - templateTXT *templatetxt.Template -} - -func (bt *builtTemplate) executeTemplateHTML(w io.Writer, content any) error { - if bt.templateHTML == nil { - file := templateFileHTML(bt.name) - templ, err := parseFromDiskHTML(file) - if err != nil { - return fmt.Errorf("Failed to parse template file: %w", err) - } - if templ == nil { - w.Write([]byte("Failed to read from disk: ")) - return errors.New("Template parsing failed") - } - //log.Debug().Str("name", templ.Name()).Msg("Parsed template") - return templ.ExecuteTemplate(w, bt.name+".html", content) - } else { - return bt.templateHTML.ExecuteTemplate(w, bt.name+".html", content) - } -} -func (bt *builtTemplate) executeTemplateTXT(w io.Writer, content any) error { - if bt.templateTXT == nil { - file := templateFileTXT(bt.name) - templ, err := parseFromDiskTXT(file) - if err != nil { - return fmt.Errorf("Failed to parse template file: %w", err) - } - if templ == nil { - w.Write([]byte("Failed to read from disk: ")) - return errors.New("Template parsing failed") - } - //log.Debug().Str("name", templ.Name()).Msg("Parsed template") - return templ.ExecuteTemplate(w, bt.name+".txt", content) - } else { - return bt.templateTXT.ExecuteTemplate(w, bt.name+".txt", content) - } -} -func templateFileHTML(name string) string { - return fmt.Sprintf("comms/template/%s.html", name) -} -func templateFileTXT(name string) string { - return fmt.Sprintf("comms/template/%s.txt", name) -} - -func buildTemplate(name string) *builtTemplate { - files_on_disk := true - file_html := templateFileHTML(name) - file_txt := templateFileTXT(name) - for _, f := range []string{file_html, file_txt} { - _, err := os.Stat(f) - if err != nil { - files_on_disk = false - if !config.IsProductionEnvironment() { - log.Warn().Str("file", f).Msg("email template file is not on disk") - } - break - } - } - var result builtTemplate - if files_on_disk { - result = builtTemplate{ - name: name, - templateHTML: nil, - templateTXT: nil, - } - } else { - result = builtTemplate{ - name: name, - templateHTML: parseEmbeddedHTML(embeddedFiles, "comms", file_html), - templateTXT: parseEmbeddedTXT(embeddedFiles, "comms", file_txt), - } - } - return &result -} - -func parseEmbeddedHTML(embeddedFiles embed.FS, subdir string, file string) *templatehtml.Template { - // Remap the file names to embedded paths - to_trim := subdir + "/" - embeddedFilePaths := []string{strings.TrimPrefix(file, to_trim)} - name := path.Base(embeddedFilePaths[0]) - log.Debug().Str("name", name).Strs("paths", embeddedFilePaths).Msg("Parsing embedded template") - return templatehtml.Must( - templatehtml.New(name).ParseFS(embeddedFiles, embeddedFilePaths...)) -} -func parseEmbeddedTXT(embeddedFiles embed.FS, subdir string, file string) *templatetxt.Template { - // Remap the file names to embedded paths - to_trim := subdir + "/" - embeddedFilePaths := []string{strings.TrimPrefix(file, to_trim)} - name := path.Base(embeddedFilePaths[0]) - log.Debug().Str("name", name).Strs("paths", embeddedFilePaths).Msg("Parsing embedded template") - return templatetxt.Must( - templatetxt.New(name).ParseFS(embeddedFiles, embeddedFilePaths...)) -} - -func parseFromDiskHTML(file string) (*templatehtml.Template, error) { - name := path.Base(file) - //log.Debug().Str("name", name).Strs("files", files).Msg("parsing from disk") - templ, err := templatehtml.New(name).ParseFiles(file) - if err != nil { - return nil, fmt.Errorf("Failed to parse %s: %w", file, err) - } - return templ, nil -} - -func parseFromDiskTXT(file string) (*templatetxt.Template, error) { - name := path.Base(file) - //log.Debug().Str("name", name).Strs("files", files).Msg("parsing from disk") - templ, err := templatetxt.New(name).ParseFiles(file) - if err != nil { - return nil, fmt.Errorf("Failed to parse %s: %w", file, err) - } - return templ, nil -} - -func renderEmailTemplates(t *builtTemplate, content interface{}) (text string, html string, err error) { - buf_txt := &bytes.Buffer{} - err = t.executeTemplateTXT(buf_txt, content) - if err != nil { - return "", "", fmt.Errorf("Failed to render TXT template: %w", err) - } - buf_html := &bytes.Buffer{} - err = t.executeTemplateHTML(buf_html, content) - if err != nil { - return "", "", fmt.Errorf("Failed to render HTML template: %w", err) - } - return buf_txt.String(), buf_html.String(), nil -} diff --git a/comms/template/initial.txt b/comms/template/initial.txt deleted file mode 100644 index eaf6a7cc..00000000 --- a/comms/template/initial.txt +++ /dev/null @@ -1 +0,0 @@ -Welcome to Report Mosquitoes Online. diff --git a/db/dberrors/comms.email.bob.go b/db/dberrors/comms.email_contact.bob.go similarity index 72% rename from db/dberrors/comms.email.bob.go rename to db/dberrors/comms.email_contact.bob.go index 09f25a12..08568a2c 100644 --- a/db/dberrors/comms.email.bob.go +++ b/db/dberrors/comms.email_contact.bob.go @@ -3,15 +3,15 @@ package dberrors -var CommsEmailErrors = &commsEmailErrors{ +var CommsEmailContactErrors = &commsEmailContactErrors{ ErrUniqueEmailPkey: &UniqueConstraintError{ schema: "comms", - table: "email", + table: "email_contact", columns: []string{"address"}, s: "email_pkey", }, } -type commsEmailErrors struct { +type commsEmailContactErrors struct { ErrUniqueEmailPkey *UniqueConstraintError } diff --git a/db/dberrors/comms.email_log.bob.go b/db/dberrors/comms.email_log.bob.go index 6948b065..29f8370c 100644 --- a/db/dberrors/comms.email_log.bob.go +++ b/db/dberrors/comms.email_log.bob.go @@ -7,7 +7,7 @@ var CommsEmailLogErrors = &commsEmailLogErrors{ ErrUniqueEmailLogPkey: &UniqueConstraintError{ schema: "comms", table: "email_log", - columns: []string{"destination", "source", "type"}, + columns: []string{"id"}, s: "email_log_pkey", }, } diff --git a/db/dberrors/comms.email_template.bob.go b/db/dberrors/comms.email_template.bob.go new file mode 100644 index 00000000..d0fe76ed --- /dev/null +++ b/db/dberrors/comms.email_template.bob.go @@ -0,0 +1,17 @@ +// Code generated by BobGen psql v0.42.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dberrors + +var CommsEmailTemplateErrors = &commsEmailTemplateErrors{ + ErrUniqueEmailTemplatePkey: &UniqueConstraintError{ + schema: "comms", + table: "email_template", + columns: []string{"id"}, + s: "email_template_pkey", + }, +} + +type commsEmailTemplateErrors struct { + ErrUniqueEmailTemplatePkey *UniqueConstraintError +} diff --git a/db/dbinfo/comms.email.bob.go b/db/dbinfo/comms.email_contact.bob.go similarity index 59% rename from db/dbinfo/comms.email.bob.go rename to db/dbinfo/comms.email_contact.bob.go index 8e5d1b15..6dff7493 100644 --- a/db/dbinfo/comms.email.bob.go +++ b/db/dbinfo/comms.email_contact.bob.go @@ -5,16 +5,16 @@ package dbinfo import "github.com/aarondl/opt/null" -var CommsEmails = Table[ - commsEmailColumns, - commsEmailIndexes, - commsEmailForeignKeys, - commsEmailUniques, - commsEmailChecks, +var CommsEmailContacts = Table[ + commsEmailContactColumns, + commsEmailContactIndexes, + commsEmailContactForeignKeys, + commsEmailContactUniques, + commsEmailContactChecks, ]{ Schema: "comms", - Name: "email", - Columns: commsEmailColumns{ + Name: "email_contact", + Columns: commsEmailContactColumns{ Address: column{ Name: "address", DBType: "text", @@ -42,8 +42,17 @@ var CommsEmails = Table[ Generated: false, AutoIncr: false, }, + PublicID: column{ + Name: "public_id", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, }, - Indexes: commsEmailIndexes{ + Indexes: commsEmailContactIndexes{ EmailPkey: index{ Type: "btree", Name: "email_pkey", @@ -71,42 +80,43 @@ var CommsEmails = Table[ Comment: "", } -type commsEmailColumns struct { +type commsEmailContactColumns struct { Address column Confirmed column IsSubscribed column + PublicID column } -func (c commsEmailColumns) AsSlice() []column { +func (c commsEmailContactColumns) AsSlice() []column { return []column{ - c.Address, c.Confirmed, c.IsSubscribed, + c.Address, c.Confirmed, c.IsSubscribed, c.PublicID, } } -type commsEmailIndexes struct { +type commsEmailContactIndexes struct { EmailPkey index } -func (i commsEmailIndexes) AsSlice() []index { +func (i commsEmailContactIndexes) AsSlice() []index { return []index{ i.EmailPkey, } } -type commsEmailForeignKeys struct{} +type commsEmailContactForeignKeys struct{} -func (f commsEmailForeignKeys) AsSlice() []foreignKey { +func (f commsEmailContactForeignKeys) AsSlice() []foreignKey { return []foreignKey{} } -type commsEmailUniques struct{} +type commsEmailContactUniques struct{} -func (u commsEmailUniques) AsSlice() []constraint { +func (u commsEmailContactUniques) AsSlice() []constraint { return []constraint{} } -type commsEmailChecks struct{} +type commsEmailContactChecks struct{} -func (c commsEmailChecks) AsSlice() []check { +func (c commsEmailContactChecks) AsSlice() []check { return []check{} } diff --git a/db/dbinfo/comms.email_log.bob.go b/db/dbinfo/comms.email_log.bob.go index 5fd8a244..09a41454 100644 --- a/db/dbinfo/comms.email_log.bob.go +++ b/db/dbinfo/comms.email_log.bob.go @@ -15,6 +15,15 @@ var CommsEmailLogs = Table[ Schema: "comms", Name: "email_log", Columns: commsEmailLogColumns{ + ID: column{ + Name: "id", + DBType: "integer", + Default: "nextval('comms.email_log_id_seq'::regclass)", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, Created: column{ Name: "created", DBType: "timestamp without time zone", @@ -24,6 +33,15 @@ var CommsEmailLogs = Table[ Generated: false, AutoIncr: false, }, + DeliveryStatus: column{ + Name: "delivery_status", + DBType: "character varying", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, Destination: column{ Name: "destination", DBType: "text", @@ -33,6 +51,24 @@ var CommsEmailLogs = Table[ Generated: false, AutoIncr: false, }, + PublicID: column{ + Name: "public_id", + DBType: "character varying", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + SentAt: column{ + Name: "sent_at", + DBType: "timestamp without time zone", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, Source: column{ Name: "source", DBType: "text", @@ -42,6 +78,33 @@ var CommsEmailLogs = Table[ Generated: false, AutoIncr: false, }, + Subject: column{ + Name: "subject", + DBType: "character varying", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + TemplateID: column{ + Name: "template_id", + DBType: "integer", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + TemplateData: column{ + Name: "template_data", + DBType: "hstore", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, Type: column{ Name: "type", DBType: "comms.messagetypeemail", @@ -58,24 +121,14 @@ var CommsEmailLogs = Table[ Name: "email_log_pkey", Columns: []indexColumn{ { - Name: "destination", - Desc: null.FromCond(false, true), - IsExpression: false, - }, - { - Name: "source", - Desc: null.FromCond(false, true), - IsExpression: false, - }, - { - Name: "type", + Name: "id", Desc: null.FromCond(false, true), IsExpression: false, }, }, Unique: true, Comment: "", - NullsFirst: []bool{false, false, false}, + NullsFirst: []bool{false}, NullsDistinct: false, Where: "", Include: []string{}, @@ -83,7 +136,7 @@ var CommsEmailLogs = Table[ }, PrimaryKey: &constraint{ Name: "email_log_pkey", - Columns: []string{"destination", "source", "type"}, + Columns: []string{"id"}, Comment: "", }, ForeignKeys: commsEmailLogForeignKeys{ @@ -93,17 +146,17 @@ var CommsEmailLogs = Table[ Columns: []string{"destination"}, Comment: "", }, - ForeignTable: "comms.email", + ForeignTable: "comms.email_contact", ForeignColumns: []string{"address"}, }, - CommsEmailLogEmailLogSourceFkey: foreignKey{ + CommsEmailLogEmailLogTemplateIDFkey: foreignKey{ constraint: constraint{ - Name: "comms.email_log.email_log_source_fkey", - Columns: []string{"source"}, + Name: "comms.email_log.email_log_template_id_fkey", + Columns: []string{"template_id"}, Comment: "", }, - ForeignTable: "comms.phone", - ForeignColumns: []string{"e164"}, + ForeignTable: "comms.email_template", + ForeignColumns: []string{"id"}, }, }, @@ -111,15 +164,22 @@ var CommsEmailLogs = Table[ } type commsEmailLogColumns struct { - Created column - Destination column - Source column - Type column + ID column + Created column + DeliveryStatus column + Destination column + PublicID column + SentAt column + Source column + Subject column + TemplateID column + TemplateData column + Type column } func (c commsEmailLogColumns) AsSlice() []column { return []column{ - c.Created, c.Destination, c.Source, c.Type, + c.ID, c.Created, c.DeliveryStatus, c.Destination, c.PublicID, c.SentAt, c.Source, c.Subject, c.TemplateID, c.TemplateData, c.Type, } } @@ -135,12 +195,12 @@ func (i commsEmailLogIndexes) AsSlice() []index { type commsEmailLogForeignKeys struct { CommsEmailLogEmailLogDestinationFkey foreignKey - CommsEmailLogEmailLogSourceFkey foreignKey + CommsEmailLogEmailLogTemplateIDFkey foreignKey } func (f commsEmailLogForeignKeys) AsSlice() []foreignKey { return []foreignKey{ - f.CommsEmailLogEmailLogDestinationFkey, f.CommsEmailLogEmailLogSourceFkey, + f.CommsEmailLogEmailLogDestinationFkey, f.CommsEmailLogEmailLogTemplateIDFkey, } } diff --git a/db/dbinfo/comms.email_template.bob.go b/db/dbinfo/comms.email_template.bob.go new file mode 100644 index 00000000..b299e2e7 --- /dev/null +++ b/db/dbinfo/comms.email_template.bob.go @@ -0,0 +1,162 @@ +// Code generated by BobGen psql v0.42.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package dbinfo + +import "github.com/aarondl/opt/null" + +var CommsEmailTemplates = Table[ + commsEmailTemplateColumns, + commsEmailTemplateIndexes, + commsEmailTemplateForeignKeys, + commsEmailTemplateUniques, + commsEmailTemplateChecks, +]{ + Schema: "comms", + Name: "email_template", + Columns: commsEmailTemplateColumns{ + ContentHTML: column{ + Name: "content_html", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + ContentTXT: column{ + Name: "content_txt", + DBType: "text", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + ContentHashHTML: column{ + Name: "content_hash_html", + DBType: "character varying", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + ContentHashTXT: column{ + Name: "content_hash_txt", + DBType: "character varying", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Created: column{ + Name: "created", + DBType: "timestamp without time zone", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + ID: column{ + Name: "id", + DBType: "integer", + Default: "nextval('comms.email_template_id_seq'::regclass)", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + Superceded: column{ + Name: "superceded", + DBType: "timestamp without time zone", + Default: "NULL", + Comment: "", + Nullable: true, + Generated: false, + AutoIncr: false, + }, + MessageType: column{ + Name: "message_type", + DBType: "comms.messagetypeemail", + Default: "", + Comment: "", + Nullable: false, + Generated: false, + AutoIncr: false, + }, + }, + Indexes: commsEmailTemplateIndexes{ + EmailTemplatePkey: index{ + Type: "btree", + Name: "email_template_pkey", + Columns: []indexColumn{ + { + Name: "id", + Desc: null.FromCond(false, true), + IsExpression: false, + }, + }, + Unique: true, + Comment: "", + NullsFirst: []bool{false}, + NullsDistinct: false, + Where: "", + Include: []string{}, + }, + }, + PrimaryKey: &constraint{ + Name: "email_template_pkey", + Columns: []string{"id"}, + Comment: "", + }, + + Comment: "", +} + +type commsEmailTemplateColumns struct { + ContentHTML column + ContentTXT column + ContentHashHTML column + ContentHashTXT column + Created column + ID column + Superceded column + MessageType column +} + +func (c commsEmailTemplateColumns) AsSlice() []column { + return []column{ + c.ContentHTML, c.ContentTXT, c.ContentHashHTML, c.ContentHashTXT, c.Created, c.ID, c.Superceded, c.MessageType, + } +} + +type commsEmailTemplateIndexes struct { + EmailTemplatePkey index +} + +func (i commsEmailTemplateIndexes) AsSlice() []index { + return []index{ + i.EmailTemplatePkey, + } +} + +type commsEmailTemplateForeignKeys struct{} + +func (f commsEmailTemplateForeignKeys) AsSlice() []foreignKey { + return []foreignKey{} +} + +type commsEmailTemplateUniques struct{} + +func (u commsEmailTemplateUniques) AsSlice() []constraint { + return []constraint{} +} + +type commsEmailTemplateChecks struct{} + +func (c commsEmailTemplateChecks) AsSlice() []check { + return []check{} +} diff --git a/db/factory/bobfactory_context.bob.go b/db/factory/bobfactory_context.bob.go index 6c9c023b..f105c35c 100644 --- a/db/factory/bobfactory_context.bob.go +++ b/db/factory/bobfactory_context.bob.go @@ -17,18 +17,21 @@ var ( arcgisUserPrivilegeWithParentsCascadingCtx = newContextual[bool]("arcgisUserPrivilegeWithParentsCascading") arcgisUserPrivilegeRelUserUserCtx = newContextual[bool]("arcgis.user_.arcgis.user_privilege.arcgis.user_privilege.user_privilege_user_id_fkey") - // Relationship Contexts for comms.email - commsEmailWithParentsCascadingCtx = newContextual[bool]("commsEmailWithParentsCascading") - commsEmailRelDestinationEmailLogsCtx = newContextual[bool]("comms.email.comms.email_log.comms.email_log.email_log_destination_fkey") + // Relationship Contexts for comms.email_contact + commsEmailContactWithParentsCascadingCtx = newContextual[bool]("commsEmailContactWithParentsCascading") + commsEmailContactRelDestinationEmailLogsCtx = newContextual[bool]("comms.email_contact.comms.email_log.comms.email_log.email_log_destination_fkey") // Relationship Contexts for comms.email_log - commsEmailLogWithParentsCascadingCtx = newContextual[bool]("commsEmailLogWithParentsCascading") - commsEmailLogRelDestinationEmailCtx = newContextual[bool]("comms.email.comms.email_log.comms.email_log.email_log_destination_fkey") - commsEmailLogRelSourcePhoneCtx = newContextual[bool]("comms.email_log.comms.phone.comms.email_log.email_log_source_fkey") + commsEmailLogWithParentsCascadingCtx = newContextual[bool]("commsEmailLogWithParentsCascading") + commsEmailLogRelDestinationEmailContactCtx = newContextual[bool]("comms.email_contact.comms.email_log.comms.email_log.email_log_destination_fkey") + commsEmailLogRelTemplateEmailTemplateCtx = newContextual[bool]("comms.email_log.comms.email_template.comms.email_log.email_log_template_id_fkey") + + // Relationship Contexts for comms.email_template + commsEmailTemplateWithParentsCascadingCtx = newContextual[bool]("commsEmailTemplateWithParentsCascading") + commsEmailTemplateRelTemplateEmailLogsCtx = newContextual[bool]("comms.email_log.comms.email_template.comms.email_log.email_log_template_id_fkey") // Relationship Contexts for comms.phone commsPhoneWithParentsCascadingCtx = newContextual[bool]("commsPhoneWithParentsCascading") - commsPhoneRelSourceEmailLogsCtx = newContextual[bool]("comms.email_log.comms.phone.comms.email_log.email_log_source_fkey") commsPhoneRelDestinationTextLogsCtx = newContextual[bool]("comms.phone.comms.text_log.comms.text_log.text_log_destination_fkey") commsPhoneRelSourceTextLogsCtx = newContextual[bool]("comms.phone.comms.text_log.comms.text_log.text_log_source_fkey") diff --git a/db/factory/bobfactory_main.bob.go b/db/factory/bobfactory_main.bob.go index d1f5124a..2f2ea083 100644 --- a/db/factory/bobfactory_main.bob.go +++ b/db/factory/bobfactory_main.bob.go @@ -15,13 +15,15 @@ import ( "github.com/lib/pq" "github.com/shopspring/decimal" "github.com/stephenafamo/bob/types" + "github.com/stephenafamo/bob/types/pgtypes" ) type Factory struct { baseArcgisUserMods ArcgisUserModSlice baseArcgisUserPrivilegeMods ArcgisUserPrivilegeModSlice - baseCommsEmailMods CommsEmailModSlice + baseCommsEmailContactMods CommsEmailContactModSlice baseCommsEmailLogMods CommsEmailLogModSlice + baseCommsEmailTemplateMods CommsEmailTemplateModSlice baseCommsPhoneMods CommsPhoneModSlice baseCommsTextLogMods CommsTextLogModSlice baseFieldseekerContainerrelateMods FieldseekerContainerrelateModSlice @@ -160,32 +162,33 @@ func (f *Factory) FromExistingArcgisUserPrivilege(m *models.ArcgisUserPrivilege) return o } -func (f *Factory) NewCommsEmail(mods ...CommsEmailMod) *CommsEmailTemplate { - return f.NewCommsEmailWithContext(context.Background(), mods...) +func (f *Factory) NewCommsEmailContact(mods ...CommsEmailContactMod) *CommsEmailContactTemplate { + return f.NewCommsEmailContactWithContext(context.Background(), mods...) } -func (f *Factory) NewCommsEmailWithContext(ctx context.Context, mods ...CommsEmailMod) *CommsEmailTemplate { - o := &CommsEmailTemplate{f: f} +func (f *Factory) NewCommsEmailContactWithContext(ctx context.Context, mods ...CommsEmailContactMod) *CommsEmailContactTemplate { + o := &CommsEmailContactTemplate{f: f} if f != nil { - f.baseCommsEmailMods.Apply(ctx, o) + f.baseCommsEmailContactMods.Apply(ctx, o) } - CommsEmailModSlice(mods).Apply(ctx, o) + CommsEmailContactModSlice(mods).Apply(ctx, o) return o } -func (f *Factory) FromExistingCommsEmail(m *models.CommsEmail) *CommsEmailTemplate { - o := &CommsEmailTemplate{f: f, alreadyPersisted: true} +func (f *Factory) FromExistingCommsEmailContact(m *models.CommsEmailContact) *CommsEmailContactTemplate { + o := &CommsEmailContactTemplate{f: f, alreadyPersisted: true} o.Address = func() string { return m.Address } o.Confirmed = func() bool { return m.Confirmed } o.IsSubscribed = func() bool { return m.IsSubscribed } + o.PublicID = func() string { return m.PublicID } ctx := context.Background() if len(m.R.DestinationEmailLogs) > 0 { - CommsEmailMods.AddExistingDestinationEmailLogs(m.R.DestinationEmailLogs...).Apply(ctx, o) + CommsEmailContactMods.AddExistingDestinationEmailLogs(m.R.DestinationEmailLogs...).Apply(ctx, o) } return o @@ -210,17 +213,60 @@ func (f *Factory) NewCommsEmailLogWithContext(ctx context.Context, mods ...Comms func (f *Factory) FromExistingCommsEmailLog(m *models.CommsEmailLog) *CommsEmailLogTemplate { o := &CommsEmailLogTemplate{f: f, alreadyPersisted: true} + o.ID = func() int32 { return m.ID } o.Created = func() time.Time { return m.Created } + o.DeliveryStatus = func() string { return m.DeliveryStatus } o.Destination = func() string { return m.Destination } + o.PublicID = func() string { return m.PublicID } + o.SentAt = func() null.Val[time.Time] { return m.SentAt } o.Source = func() string { return m.Source } + o.Subject = func() string { return m.Subject } + o.TemplateID = func() null.Val[int32] { return m.TemplateID } + o.TemplateData = func() pgtypes.HStore { return m.TemplateData } o.Type = func() enums.CommsMessagetypeemail { return m.Type } ctx := context.Background() - if m.R.DestinationEmail != nil { - CommsEmailLogMods.WithExistingDestinationEmail(m.R.DestinationEmail).Apply(ctx, o) + if m.R.DestinationEmailContact != nil { + CommsEmailLogMods.WithExistingDestinationEmailContact(m.R.DestinationEmailContact).Apply(ctx, o) } - if m.R.SourcePhone != nil { - CommsEmailLogMods.WithExistingSourcePhone(m.R.SourcePhone).Apply(ctx, o) + if m.R.TemplateEmailTemplate != nil { + CommsEmailLogMods.WithExistingTemplateEmailTemplate(m.R.TemplateEmailTemplate).Apply(ctx, o) + } + + return o +} + +func (f *Factory) NewCommsEmailTemplate(mods ...CommsEmailTemplateMod) *CommsEmailTemplateTemplate { + return f.NewCommsEmailTemplateWithContext(context.Background(), mods...) +} + +func (f *Factory) NewCommsEmailTemplateWithContext(ctx context.Context, mods ...CommsEmailTemplateMod) *CommsEmailTemplateTemplate { + o := &CommsEmailTemplateTemplate{f: f} + + if f != nil { + f.baseCommsEmailTemplateMods.Apply(ctx, o) + } + + CommsEmailTemplateModSlice(mods).Apply(ctx, o) + + return o +} + +func (f *Factory) FromExistingCommsEmailTemplate(m *models.CommsEmailTemplate) *CommsEmailTemplateTemplate { + o := &CommsEmailTemplateTemplate{f: f, alreadyPersisted: true} + + o.ContentHTML = func() string { return m.ContentHTML } + o.ContentTXT = func() string { return m.ContentTXT } + o.ContentHashHTML = func() string { return m.ContentHashHTML } + o.ContentHashTXT = func() string { return m.ContentHashTXT } + o.Created = func() time.Time { return m.Created } + o.ID = func() int32 { return m.ID } + o.Superceded = func() null.Val[time.Time] { return m.Superceded } + o.MessageType = func() enums.CommsMessagetypeemail { return m.MessageType } + + ctx := context.Background() + if len(m.R.TemplateEmailLogs) > 0 { + CommsEmailTemplateMods.AddExistingTemplateEmailLogs(m.R.TemplateEmailLogs...).Apply(ctx, o) } return o @@ -249,9 +295,6 @@ func (f *Factory) FromExistingCommsPhone(m *models.CommsPhone) *CommsPhoneTempla o.IsSubscribed = func() bool { return m.IsSubscribed } ctx := context.Background() - if len(m.R.SourceEmailLogs) > 0 { - CommsPhoneMods.AddExistingSourceEmailLogs(m.R.SourceEmailLogs...).Apply(ctx, o) - } if len(m.R.DestinationTextLogs) > 0 { CommsPhoneMods.AddExistingDestinationTextLogs(m.R.DestinationTextLogs...).Apply(ctx, o) } @@ -3198,12 +3241,12 @@ func (f *Factory) AddBaseArcgisUserPrivilegeMod(mods ...ArcgisUserPrivilegeMod) f.baseArcgisUserPrivilegeMods = append(f.baseArcgisUserPrivilegeMods, mods...) } -func (f *Factory) ClearBaseCommsEmailMods() { - f.baseCommsEmailMods = nil +func (f *Factory) ClearBaseCommsEmailContactMods() { + f.baseCommsEmailContactMods = nil } -func (f *Factory) AddBaseCommsEmailMod(mods ...CommsEmailMod) { - f.baseCommsEmailMods = append(f.baseCommsEmailMods, mods...) +func (f *Factory) AddBaseCommsEmailContactMod(mods ...CommsEmailContactMod) { + f.baseCommsEmailContactMods = append(f.baseCommsEmailContactMods, mods...) } func (f *Factory) ClearBaseCommsEmailLogMods() { @@ -3214,6 +3257,14 @@ func (f *Factory) AddBaseCommsEmailLogMod(mods ...CommsEmailLogMod) { f.baseCommsEmailLogMods = append(f.baseCommsEmailLogMods, mods...) } +func (f *Factory) ClearBaseCommsEmailTemplateMods() { + f.baseCommsEmailTemplateMods = nil +} + +func (f *Factory) AddBaseCommsEmailTemplateMod(mods ...CommsEmailTemplateMod) { + f.baseCommsEmailTemplateMods = append(f.baseCommsEmailTemplateMods, mods...) +} + func (f *Factory) ClearBaseCommsPhoneMods() { f.baseCommsPhoneMods = nil } diff --git a/db/factory/bobfactory_random.bob.go b/db/factory/bobfactory_random.bob.go index 120f1c21..dfa5ebc5 100644 --- a/db/factory/bobfactory_random.bob.go +++ b/db/factory/bobfactory_random.bob.go @@ -5,6 +5,7 @@ package factory import ( "bytes" + "database/sql" "encoding/json" "fmt" "math" @@ -18,6 +19,7 @@ import ( "github.com/lib/pq" "github.com/shopspring/decimal" "github.com/stephenafamo/bob/types" + "github.com/stephenafamo/bob/types/pgtypes" ) var defaultFaker = faker.New() @@ -281,6 +283,18 @@ func random_int64(f *faker.Faker, limits ...string) int64 { return f.Int64() } +func random_pgtypes_HStore(f *faker.Faker, limits ...string) pgtypes.HStore { + if f == nil { + f = &defaultFaker + } + + hs := make(pgtypes.HStore) + for range f.IntBetween(1, 5) { + hs[random_string(f)] = sql.Null[string]{V: random_string(f, limits...), Valid: f.Bool()} + } + return hs +} + func random_pq_BoolArray(f *faker.Faker, limits ...string) pq.BoolArray { if f == nil { f = &defaultFaker diff --git a/db/factory/comms.email.bob.go b/db/factory/comms.email.bob.go deleted file mode 100644 index 610aae07..00000000 --- a/db/factory/comms.email.bob.go +++ /dev/null @@ -1,434 +0,0 @@ -// Code generated by BobGen psql v0.42.1. DO NOT EDIT. -// This file is meant to be re-generated in place and/or deleted at any time. - -package factory - -import ( - "context" - "testing" - - models "github.com/Gleipnir-Technology/nidus-sync/db/models" - "github.com/aarondl/opt/omit" - "github.com/jaswdr/faker/v2" - "github.com/stephenafamo/bob" -) - -type CommsEmailMod interface { - Apply(context.Context, *CommsEmailTemplate) -} - -type CommsEmailModFunc func(context.Context, *CommsEmailTemplate) - -func (f CommsEmailModFunc) Apply(ctx context.Context, n *CommsEmailTemplate) { - f(ctx, n) -} - -type CommsEmailModSlice []CommsEmailMod - -func (mods CommsEmailModSlice) Apply(ctx context.Context, n *CommsEmailTemplate) { - for _, f := range mods { - f.Apply(ctx, n) - } -} - -// CommsEmailTemplate is an object representing the database table. -// all columns are optional and should be set by mods -type CommsEmailTemplate struct { - Address func() string - Confirmed func() bool - IsSubscribed func() bool - - r commsEmailR - f *Factory - - alreadyPersisted bool -} - -type commsEmailR struct { - DestinationEmailLogs []*commsEmailRDestinationEmailLogsR -} - -type commsEmailRDestinationEmailLogsR struct { - number int - o *CommsEmailLogTemplate -} - -// Apply mods to the CommsEmailTemplate -func (o *CommsEmailTemplate) Apply(ctx context.Context, mods ...CommsEmailMod) { - for _, mod := range mods { - mod.Apply(ctx, o) - } -} - -// setModelRels creates and sets the relationships on *models.CommsEmail -// according to the relationships in the template. Nothing is inserted into the db -func (t CommsEmailTemplate) setModelRels(o *models.CommsEmail) { - if t.r.DestinationEmailLogs != nil { - rel := models.CommsEmailLogSlice{} - for _, r := range t.r.DestinationEmailLogs { - related := r.o.BuildMany(r.number) - for _, rel := range related { - rel.Destination = o.Address // h2 - rel.R.DestinationEmail = o - } - rel = append(rel, related...) - } - o.R.DestinationEmailLogs = rel - } -} - -// BuildSetter returns an *models.CommsEmailSetter -// this does nothing with the relationship templates -func (o CommsEmailTemplate) BuildSetter() *models.CommsEmailSetter { - m := &models.CommsEmailSetter{} - - if o.Address != nil { - val := o.Address() - m.Address = omit.From(val) - } - if o.Confirmed != nil { - val := o.Confirmed() - m.Confirmed = omit.From(val) - } - if o.IsSubscribed != nil { - val := o.IsSubscribed() - m.IsSubscribed = omit.From(val) - } - - return m -} - -// BuildManySetter returns an []*models.CommsEmailSetter -// this does nothing with the relationship templates -func (o CommsEmailTemplate) BuildManySetter(number int) []*models.CommsEmailSetter { - m := make([]*models.CommsEmailSetter, number) - - for i := range m { - m[i] = o.BuildSetter() - } - - return m -} - -// Build returns an *models.CommsEmail -// Related objects are also created and placed in the .R field -// NOTE: Objects are not inserted into the database. Use CommsEmailTemplate.Create -func (o CommsEmailTemplate) Build() *models.CommsEmail { - m := &models.CommsEmail{} - - if o.Address != nil { - m.Address = o.Address() - } - if o.Confirmed != nil { - m.Confirmed = o.Confirmed() - } - if o.IsSubscribed != nil { - m.IsSubscribed = o.IsSubscribed() - } - - o.setModelRels(m) - - return m -} - -// BuildMany returns an models.CommsEmailSlice -// Related objects are also created and placed in the .R field -// NOTE: Objects are not inserted into the database. Use CommsEmailTemplate.CreateMany -func (o CommsEmailTemplate) BuildMany(number int) models.CommsEmailSlice { - m := make(models.CommsEmailSlice, number) - - for i := range m { - m[i] = o.Build() - } - - return m -} - -func ensureCreatableCommsEmail(m *models.CommsEmailSetter) { - if !(m.Address.IsValue()) { - val := random_string(nil) - m.Address = omit.From(val) - } - if !(m.Confirmed.IsValue()) { - val := random_bool(nil) - m.Confirmed = omit.From(val) - } - if !(m.IsSubscribed.IsValue()) { - val := random_bool(nil) - m.IsSubscribed = omit.From(val) - } -} - -// insertOptRels creates and inserts any optional the relationships on *models.CommsEmail -// according to the relationships in the template. -// any required relationship should have already exist on the model -func (o *CommsEmailTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.CommsEmail) error { - var err error - - isDestinationEmailLogsDone, _ := commsEmailRelDestinationEmailLogsCtx.Value(ctx) - if !isDestinationEmailLogsDone && o.r.DestinationEmailLogs != nil { - ctx = commsEmailRelDestinationEmailLogsCtx.WithValue(ctx, true) - for _, r := range o.r.DestinationEmailLogs { - if r.o.alreadyPersisted { - m.R.DestinationEmailLogs = append(m.R.DestinationEmailLogs, r.o.Build()) - } else { - rel0, err := r.o.CreateMany(ctx, exec, r.number) - if err != nil { - return err - } - - err = m.AttachDestinationEmailLogs(ctx, exec, rel0...) - if err != nil { - return err - } - } - } - } - - return err -} - -// Create builds a commsEmail and inserts it into the database -// Relations objects are also inserted and placed in the .R field -func (o *CommsEmailTemplate) Create(ctx context.Context, exec bob.Executor) (*models.CommsEmail, error) { - var err error - opt := o.BuildSetter() - ensureCreatableCommsEmail(opt) - - m, err := models.CommsEmails.Insert(opt).One(ctx, exec) - if err != nil { - return nil, err - } - - if err := o.insertOptRels(ctx, exec, m); err != nil { - return nil, err - } - return m, err -} - -// MustCreate builds a commsEmail and inserts it into the database -// Relations objects are also inserted and placed in the .R field -// panics if an error occurs -func (o *CommsEmailTemplate) MustCreate(ctx context.Context, exec bob.Executor) *models.CommsEmail { - m, err := o.Create(ctx, exec) - if err != nil { - panic(err) - } - return m -} - -// CreateOrFail builds a commsEmail and inserts it into the database -// Relations objects are also inserted and placed in the .R field -// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs -func (o *CommsEmailTemplate) CreateOrFail(ctx context.Context, tb testing.TB, exec bob.Executor) *models.CommsEmail { - tb.Helper() - m, err := o.Create(ctx, exec) - if err != nil { - tb.Fatal(err) - return nil - } - return m -} - -// CreateMany builds multiple commsEmails and inserts them into the database -// Relations objects are also inserted and placed in the .R field -func (o CommsEmailTemplate) CreateMany(ctx context.Context, exec bob.Executor, number int) (models.CommsEmailSlice, error) { - var err error - m := make(models.CommsEmailSlice, number) - - for i := range m { - m[i], err = o.Create(ctx, exec) - if err != nil { - return nil, err - } - } - - return m, nil -} - -// MustCreateMany builds multiple commsEmails and inserts them into the database -// Relations objects are also inserted and placed in the .R field -// panics if an error occurs -func (o CommsEmailTemplate) MustCreateMany(ctx context.Context, exec bob.Executor, number int) models.CommsEmailSlice { - m, err := o.CreateMany(ctx, exec, number) - if err != nil { - panic(err) - } - return m -} - -// CreateManyOrFail builds multiple commsEmails and inserts them into the database -// Relations objects are also inserted and placed in the .R field -// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs -func (o CommsEmailTemplate) CreateManyOrFail(ctx context.Context, tb testing.TB, exec bob.Executor, number int) models.CommsEmailSlice { - tb.Helper() - m, err := o.CreateMany(ctx, exec, number) - if err != nil { - tb.Fatal(err) - return nil - } - return m -} - -// CommsEmail has methods that act as mods for the CommsEmailTemplate -var CommsEmailMods commsEmailMods - -type commsEmailMods struct{} - -func (m commsEmailMods) RandomizeAllColumns(f *faker.Faker) CommsEmailMod { - return CommsEmailModSlice{ - CommsEmailMods.RandomAddress(f), - CommsEmailMods.RandomConfirmed(f), - CommsEmailMods.RandomIsSubscribed(f), - } -} - -// Set the model columns to this value -func (m commsEmailMods) Address(val string) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Address = func() string { return val } - }) -} - -// Set the Column from the function -func (m commsEmailMods) AddressFunc(f func() string) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Address = f - }) -} - -// Clear any values for the column -func (m commsEmailMods) UnsetAddress() CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Address = nil - }) -} - -// Generates a random value for the column using the given faker -// if faker is nil, a default faker is used -func (m commsEmailMods) RandomAddress(f *faker.Faker) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Address = func() string { - return random_string(f) - } - }) -} - -// Set the model columns to this value -func (m commsEmailMods) Confirmed(val bool) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Confirmed = func() bool { return val } - }) -} - -// Set the Column from the function -func (m commsEmailMods) ConfirmedFunc(f func() bool) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Confirmed = f - }) -} - -// Clear any values for the column -func (m commsEmailMods) UnsetConfirmed() CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Confirmed = nil - }) -} - -// Generates a random value for the column using the given faker -// if faker is nil, a default faker is used -func (m commsEmailMods) RandomConfirmed(f *faker.Faker) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.Confirmed = func() bool { - return random_bool(f) - } - }) -} - -// Set the model columns to this value -func (m commsEmailMods) IsSubscribed(val bool) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.IsSubscribed = func() bool { return val } - }) -} - -// Set the Column from the function -func (m commsEmailMods) IsSubscribedFunc(f func() bool) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.IsSubscribed = f - }) -} - -// Clear any values for the column -func (m commsEmailMods) UnsetIsSubscribed() CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.IsSubscribed = nil - }) -} - -// Generates a random value for the column using the given faker -// if faker is nil, a default faker is used -func (m commsEmailMods) RandomIsSubscribed(f *faker.Faker) CommsEmailMod { - return CommsEmailModFunc(func(_ context.Context, o *CommsEmailTemplate) { - o.IsSubscribed = func() bool { - return random_bool(f) - } - }) -} - -func (m commsEmailMods) WithParentsCascading() CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - if isDone, _ := commsEmailWithParentsCascadingCtx.Value(ctx); isDone { - return - } - ctx = commsEmailWithParentsCascadingCtx.WithValue(ctx, true) - }) -} - -func (m commsEmailMods) WithDestinationEmailLogs(number int, related *CommsEmailLogTemplate) CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - o.r.DestinationEmailLogs = []*commsEmailRDestinationEmailLogsR{{ - number: number, - o: related, - }} - }) -} - -func (m commsEmailMods) WithNewDestinationEmailLogs(number int, mods ...CommsEmailLogMod) CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - related := o.f.NewCommsEmailLogWithContext(ctx, mods...) - m.WithDestinationEmailLogs(number, related).Apply(ctx, o) - }) -} - -func (m commsEmailMods) AddDestinationEmailLogs(number int, related *CommsEmailLogTemplate) CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - o.r.DestinationEmailLogs = append(o.r.DestinationEmailLogs, &commsEmailRDestinationEmailLogsR{ - number: number, - o: related, - }) - }) -} - -func (m commsEmailMods) AddNewDestinationEmailLogs(number int, mods ...CommsEmailLogMod) CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - related := o.f.NewCommsEmailLogWithContext(ctx, mods...) - m.AddDestinationEmailLogs(number, related).Apply(ctx, o) - }) -} - -func (m commsEmailMods) AddExistingDestinationEmailLogs(existingModels ...*models.CommsEmailLog) CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - for _, em := range existingModels { - o.r.DestinationEmailLogs = append(o.r.DestinationEmailLogs, &commsEmailRDestinationEmailLogsR{ - o: o.f.FromExistingCommsEmailLog(em), - }) - } - }) -} - -func (m commsEmailMods) WithoutDestinationEmailLogs() CommsEmailMod { - return CommsEmailModFunc(func(ctx context.Context, o *CommsEmailTemplate) { - o.r.DestinationEmailLogs = nil - }) -} diff --git a/db/factory/comms.email_contact.bob.go b/db/factory/comms.email_contact.bob.go new file mode 100644 index 00000000..11a7fe1d --- /dev/null +++ b/db/factory/comms.email_contact.bob.go @@ -0,0 +1,478 @@ +// Code generated by BobGen psql v0.42.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package factory + +import ( + "context" + "testing" + + models "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/aarondl/opt/omit" + "github.com/jaswdr/faker/v2" + "github.com/stephenafamo/bob" +) + +type CommsEmailContactMod interface { + Apply(context.Context, *CommsEmailContactTemplate) +} + +type CommsEmailContactModFunc func(context.Context, *CommsEmailContactTemplate) + +func (f CommsEmailContactModFunc) Apply(ctx context.Context, n *CommsEmailContactTemplate) { + f(ctx, n) +} + +type CommsEmailContactModSlice []CommsEmailContactMod + +func (mods CommsEmailContactModSlice) Apply(ctx context.Context, n *CommsEmailContactTemplate) { + for _, f := range mods { + f.Apply(ctx, n) + } +} + +// CommsEmailContactTemplate is an object representing the database table. +// all columns are optional and should be set by mods +type CommsEmailContactTemplate struct { + Address func() string + Confirmed func() bool + IsSubscribed func() bool + PublicID func() string + + r commsEmailContactR + f *Factory + + alreadyPersisted bool +} + +type commsEmailContactR struct { + DestinationEmailLogs []*commsEmailContactRDestinationEmailLogsR +} + +type commsEmailContactRDestinationEmailLogsR struct { + number int + o *CommsEmailLogTemplate +} + +// Apply mods to the CommsEmailContactTemplate +func (o *CommsEmailContactTemplate) Apply(ctx context.Context, mods ...CommsEmailContactMod) { + for _, mod := range mods { + mod.Apply(ctx, o) + } +} + +// setModelRels creates and sets the relationships on *models.CommsEmailContact +// according to the relationships in the template. Nothing is inserted into the db +func (t CommsEmailContactTemplate) setModelRels(o *models.CommsEmailContact) { + if t.r.DestinationEmailLogs != nil { + rel := models.CommsEmailLogSlice{} + for _, r := range t.r.DestinationEmailLogs { + related := r.o.BuildMany(r.number) + for _, rel := range related { + rel.Destination = o.Address // h2 + rel.R.DestinationEmailContact = o + } + rel = append(rel, related...) + } + o.R.DestinationEmailLogs = rel + } +} + +// BuildSetter returns an *models.CommsEmailContactSetter +// this does nothing with the relationship templates +func (o CommsEmailContactTemplate) BuildSetter() *models.CommsEmailContactSetter { + m := &models.CommsEmailContactSetter{} + + if o.Address != nil { + val := o.Address() + m.Address = omit.From(val) + } + if o.Confirmed != nil { + val := o.Confirmed() + m.Confirmed = omit.From(val) + } + if o.IsSubscribed != nil { + val := o.IsSubscribed() + m.IsSubscribed = omit.From(val) + } + if o.PublicID != nil { + val := o.PublicID() + m.PublicID = omit.From(val) + } + + return m +} + +// BuildManySetter returns an []*models.CommsEmailContactSetter +// this does nothing with the relationship templates +func (o CommsEmailContactTemplate) BuildManySetter(number int) []*models.CommsEmailContactSetter { + m := make([]*models.CommsEmailContactSetter, number) + + for i := range m { + m[i] = o.BuildSetter() + } + + return m +} + +// Build returns an *models.CommsEmailContact +// Related objects are also created and placed in the .R field +// NOTE: Objects are not inserted into the database. Use CommsEmailContactTemplate.Create +func (o CommsEmailContactTemplate) Build() *models.CommsEmailContact { + m := &models.CommsEmailContact{} + + if o.Address != nil { + m.Address = o.Address() + } + if o.Confirmed != nil { + m.Confirmed = o.Confirmed() + } + if o.IsSubscribed != nil { + m.IsSubscribed = o.IsSubscribed() + } + if o.PublicID != nil { + m.PublicID = o.PublicID() + } + + o.setModelRels(m) + + return m +} + +// BuildMany returns an models.CommsEmailContactSlice +// Related objects are also created and placed in the .R field +// NOTE: Objects are not inserted into the database. Use CommsEmailContactTemplate.CreateMany +func (o CommsEmailContactTemplate) BuildMany(number int) models.CommsEmailContactSlice { + m := make(models.CommsEmailContactSlice, number) + + for i := range m { + m[i] = o.Build() + } + + return m +} + +func ensureCreatableCommsEmailContact(m *models.CommsEmailContactSetter) { + if !(m.Address.IsValue()) { + val := random_string(nil) + m.Address = omit.From(val) + } + if !(m.Confirmed.IsValue()) { + val := random_bool(nil) + m.Confirmed = omit.From(val) + } + if !(m.IsSubscribed.IsValue()) { + val := random_bool(nil) + m.IsSubscribed = omit.From(val) + } + if !(m.PublicID.IsValue()) { + val := random_string(nil) + m.PublicID = omit.From(val) + } +} + +// insertOptRels creates and inserts any optional the relationships on *models.CommsEmailContact +// according to the relationships in the template. +// any required relationship should have already exist on the model +func (o *CommsEmailContactTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.CommsEmailContact) error { + var err error + + isDestinationEmailLogsDone, _ := commsEmailContactRelDestinationEmailLogsCtx.Value(ctx) + if !isDestinationEmailLogsDone && o.r.DestinationEmailLogs != nil { + ctx = commsEmailContactRelDestinationEmailLogsCtx.WithValue(ctx, true) + for _, r := range o.r.DestinationEmailLogs { + if r.o.alreadyPersisted { + m.R.DestinationEmailLogs = append(m.R.DestinationEmailLogs, r.o.Build()) + } else { + rel0, err := r.o.CreateMany(ctx, exec, r.number) + if err != nil { + return err + } + + err = m.AttachDestinationEmailLogs(ctx, exec, rel0...) + if err != nil { + return err + } + } + } + } + + return err +} + +// Create builds a commsEmailContact and inserts it into the database +// Relations objects are also inserted and placed in the .R field +func (o *CommsEmailContactTemplate) Create(ctx context.Context, exec bob.Executor) (*models.CommsEmailContact, error) { + var err error + opt := o.BuildSetter() + ensureCreatableCommsEmailContact(opt) + + m, err := models.CommsEmailContacts.Insert(opt).One(ctx, exec) + if err != nil { + return nil, err + } + + if err := o.insertOptRels(ctx, exec, m); err != nil { + return nil, err + } + return m, err +} + +// MustCreate builds a commsEmailContact and inserts it into the database +// Relations objects are also inserted and placed in the .R field +// panics if an error occurs +func (o *CommsEmailContactTemplate) MustCreate(ctx context.Context, exec bob.Executor) *models.CommsEmailContact { + m, err := o.Create(ctx, exec) + if err != nil { + panic(err) + } + return m +} + +// CreateOrFail builds a commsEmailContact and inserts it into the database +// Relations objects are also inserted and placed in the .R field +// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs +func (o *CommsEmailContactTemplate) CreateOrFail(ctx context.Context, tb testing.TB, exec bob.Executor) *models.CommsEmailContact { + tb.Helper() + m, err := o.Create(ctx, exec) + if err != nil { + tb.Fatal(err) + return nil + } + return m +} + +// CreateMany builds multiple commsEmailContacts and inserts them into the database +// Relations objects are also inserted and placed in the .R field +func (o CommsEmailContactTemplate) CreateMany(ctx context.Context, exec bob.Executor, number int) (models.CommsEmailContactSlice, error) { + var err error + m := make(models.CommsEmailContactSlice, number) + + for i := range m { + m[i], err = o.Create(ctx, exec) + if err != nil { + return nil, err + } + } + + return m, nil +} + +// MustCreateMany builds multiple commsEmailContacts and inserts them into the database +// Relations objects are also inserted and placed in the .R field +// panics if an error occurs +func (o CommsEmailContactTemplate) MustCreateMany(ctx context.Context, exec bob.Executor, number int) models.CommsEmailContactSlice { + m, err := o.CreateMany(ctx, exec, number) + if err != nil { + panic(err) + } + return m +} + +// CreateManyOrFail builds multiple commsEmailContacts and inserts them into the database +// Relations objects are also inserted and placed in the .R field +// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs +func (o CommsEmailContactTemplate) CreateManyOrFail(ctx context.Context, tb testing.TB, exec bob.Executor, number int) models.CommsEmailContactSlice { + tb.Helper() + m, err := o.CreateMany(ctx, exec, number) + if err != nil { + tb.Fatal(err) + return nil + } + return m +} + +// CommsEmailContact has methods that act as mods for the CommsEmailContactTemplate +var CommsEmailContactMods commsEmailContactMods + +type commsEmailContactMods struct{} + +func (m commsEmailContactMods) RandomizeAllColumns(f *faker.Faker) CommsEmailContactMod { + return CommsEmailContactModSlice{ + CommsEmailContactMods.RandomAddress(f), + CommsEmailContactMods.RandomConfirmed(f), + CommsEmailContactMods.RandomIsSubscribed(f), + CommsEmailContactMods.RandomPublicID(f), + } +} + +// Set the model columns to this value +func (m commsEmailContactMods) Address(val string) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Address = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailContactMods) AddressFunc(f func() string) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Address = f + }) +} + +// Clear any values for the column +func (m commsEmailContactMods) UnsetAddress() CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Address = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailContactMods) RandomAddress(f *faker.Faker) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Address = func() string { + return random_string(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailContactMods) Confirmed(val bool) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Confirmed = func() bool { return val } + }) +} + +// Set the Column from the function +func (m commsEmailContactMods) ConfirmedFunc(f func() bool) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Confirmed = f + }) +} + +// Clear any values for the column +func (m commsEmailContactMods) UnsetConfirmed() CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Confirmed = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailContactMods) RandomConfirmed(f *faker.Faker) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.Confirmed = func() bool { + return random_bool(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailContactMods) IsSubscribed(val bool) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.IsSubscribed = func() bool { return val } + }) +} + +// Set the Column from the function +func (m commsEmailContactMods) IsSubscribedFunc(f func() bool) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.IsSubscribed = f + }) +} + +// Clear any values for the column +func (m commsEmailContactMods) UnsetIsSubscribed() CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.IsSubscribed = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailContactMods) RandomIsSubscribed(f *faker.Faker) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.IsSubscribed = func() bool { + return random_bool(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailContactMods) PublicID(val string) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.PublicID = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailContactMods) PublicIDFunc(f func() string) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.PublicID = f + }) +} + +// Clear any values for the column +func (m commsEmailContactMods) UnsetPublicID() CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.PublicID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailContactMods) RandomPublicID(f *faker.Faker) CommsEmailContactMod { + return CommsEmailContactModFunc(func(_ context.Context, o *CommsEmailContactTemplate) { + o.PublicID = func() string { + return random_string(f) + } + }) +} + +func (m commsEmailContactMods) WithParentsCascading() CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + if isDone, _ := commsEmailContactWithParentsCascadingCtx.Value(ctx); isDone { + return + } + ctx = commsEmailContactWithParentsCascadingCtx.WithValue(ctx, true) + }) +} + +func (m commsEmailContactMods) WithDestinationEmailLogs(number int, related *CommsEmailLogTemplate) CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + o.r.DestinationEmailLogs = []*commsEmailContactRDestinationEmailLogsR{{ + number: number, + o: related, + }} + }) +} + +func (m commsEmailContactMods) WithNewDestinationEmailLogs(number int, mods ...CommsEmailLogMod) CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + related := o.f.NewCommsEmailLogWithContext(ctx, mods...) + m.WithDestinationEmailLogs(number, related).Apply(ctx, o) + }) +} + +func (m commsEmailContactMods) AddDestinationEmailLogs(number int, related *CommsEmailLogTemplate) CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + o.r.DestinationEmailLogs = append(o.r.DestinationEmailLogs, &commsEmailContactRDestinationEmailLogsR{ + number: number, + o: related, + }) + }) +} + +func (m commsEmailContactMods) AddNewDestinationEmailLogs(number int, mods ...CommsEmailLogMod) CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + related := o.f.NewCommsEmailLogWithContext(ctx, mods...) + m.AddDestinationEmailLogs(number, related).Apply(ctx, o) + }) +} + +func (m commsEmailContactMods) AddExistingDestinationEmailLogs(existingModels ...*models.CommsEmailLog) CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + for _, em := range existingModels { + o.r.DestinationEmailLogs = append(o.r.DestinationEmailLogs, &commsEmailContactRDestinationEmailLogsR{ + o: o.f.FromExistingCommsEmailLog(em), + }) + } + }) +} + +func (m commsEmailContactMods) WithoutDestinationEmailLogs() CommsEmailContactMod { + return CommsEmailContactModFunc(func(ctx context.Context, o *CommsEmailContactTemplate) { + o.r.DestinationEmailLogs = nil + }) +} diff --git a/db/factory/comms.email_log.bob.go b/db/factory/comms.email_log.bob.go index 07f72bdb..13d3e040 100644 --- a/db/factory/comms.email_log.bob.go +++ b/db/factory/comms.email_log.bob.go @@ -10,9 +10,12 @@ import ( enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" models "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/aarondl/opt/null" "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" "github.com/jaswdr/faker/v2" "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/types/pgtypes" ) type CommsEmailLogMod interface { @@ -36,10 +39,17 @@ func (mods CommsEmailLogModSlice) Apply(ctx context.Context, n *CommsEmailLogTem // CommsEmailLogTemplate is an object representing the database table. // all columns are optional and should be set by mods type CommsEmailLogTemplate struct { - Created func() time.Time - Destination func() string - Source func() string - Type func() enums.CommsMessagetypeemail + ID func() int32 + Created func() time.Time + DeliveryStatus func() string + Destination func() string + PublicID func() string + SentAt func() null.Val[time.Time] + Source func() string + Subject func() string + TemplateID func() null.Val[int32] + TemplateData func() pgtypes.HStore + Type func() enums.CommsMessagetypeemail r commsEmailLogR f *Factory @@ -48,15 +58,15 @@ type CommsEmailLogTemplate struct { } type commsEmailLogR struct { - DestinationEmail *commsEmailLogRDestinationEmailR - SourcePhone *commsEmailLogRSourcePhoneR + DestinationEmailContact *commsEmailLogRDestinationEmailContactR + TemplateEmailTemplate *commsEmailLogRTemplateEmailTemplateR } -type commsEmailLogRDestinationEmailR struct { - o *CommsEmailTemplate +type commsEmailLogRDestinationEmailContactR struct { + o *CommsEmailContactTemplate } -type commsEmailLogRSourcePhoneR struct { - o *CommsPhoneTemplate +type commsEmailLogRTemplateEmailTemplateR struct { + o *CommsEmailTemplateTemplate } // Apply mods to the CommsEmailLogTemplate @@ -69,18 +79,18 @@ func (o *CommsEmailLogTemplate) Apply(ctx context.Context, mods ...CommsEmailLog // setModelRels creates and sets the relationships on *models.CommsEmailLog // according to the relationships in the template. Nothing is inserted into the db func (t CommsEmailLogTemplate) setModelRels(o *models.CommsEmailLog) { - if t.r.DestinationEmail != nil { - rel := t.r.DestinationEmail.o.Build() + if t.r.DestinationEmailContact != nil { + rel := t.r.DestinationEmailContact.o.Build() rel.R.DestinationEmailLogs = append(rel.R.DestinationEmailLogs, o) o.Destination = rel.Address // h2 - o.R.DestinationEmail = rel + o.R.DestinationEmailContact = rel } - if t.r.SourcePhone != nil { - rel := t.r.SourcePhone.o.Build() - rel.R.SourceEmailLogs = append(rel.R.SourceEmailLogs, o) - o.Source = rel.E164 // h2 - o.R.SourcePhone = rel + if t.r.TemplateEmailTemplate != nil { + rel := t.r.TemplateEmailTemplate.o.Build() + rel.R.TemplateEmailLogs = append(rel.R.TemplateEmailLogs, o) + o.TemplateID = null.From(rel.ID) // h2 + o.R.TemplateEmailTemplate = rel } } @@ -89,18 +99,46 @@ func (t CommsEmailLogTemplate) setModelRels(o *models.CommsEmailLog) { func (o CommsEmailLogTemplate) BuildSetter() *models.CommsEmailLogSetter { m := &models.CommsEmailLogSetter{} + if o.ID != nil { + val := o.ID() + m.ID = omit.From(val) + } if o.Created != nil { val := o.Created() m.Created = omit.From(val) } + if o.DeliveryStatus != nil { + val := o.DeliveryStatus() + m.DeliveryStatus = omit.From(val) + } if o.Destination != nil { val := o.Destination() m.Destination = omit.From(val) } + if o.PublicID != nil { + val := o.PublicID() + m.PublicID = omit.From(val) + } + if o.SentAt != nil { + val := o.SentAt() + m.SentAt = omitnull.FromNull(val) + } if o.Source != nil { val := o.Source() m.Source = omit.From(val) } + if o.Subject != nil { + val := o.Subject() + m.Subject = omit.From(val) + } + if o.TemplateID != nil { + val := o.TemplateID() + m.TemplateID = omitnull.FromNull(val) + } + if o.TemplateData != nil { + val := o.TemplateData() + m.TemplateData = omit.From(val) + } if o.Type != nil { val := o.Type() m.Type = omit.From(val) @@ -127,15 +165,36 @@ func (o CommsEmailLogTemplate) BuildManySetter(number int) []*models.CommsEmailL func (o CommsEmailLogTemplate) Build() *models.CommsEmailLog { m := &models.CommsEmailLog{} + if o.ID != nil { + m.ID = o.ID() + } if o.Created != nil { m.Created = o.Created() } + if o.DeliveryStatus != nil { + m.DeliveryStatus = o.DeliveryStatus() + } if o.Destination != nil { m.Destination = o.Destination() } + if o.PublicID != nil { + m.PublicID = o.PublicID() + } + if o.SentAt != nil { + m.SentAt = o.SentAt() + } if o.Source != nil { m.Source = o.Source() } + if o.Subject != nil { + m.Subject = o.Subject() + } + if o.TemplateID != nil { + m.TemplateID = o.TemplateID() + } + if o.TemplateData != nil { + m.TemplateData = o.TemplateData() + } if o.Type != nil { m.Type = o.Type() } @@ -163,14 +222,30 @@ func ensureCreatableCommsEmailLog(m *models.CommsEmailLogSetter) { val := random_time_Time(nil) m.Created = omit.From(val) } + if !(m.DeliveryStatus.IsValue()) { + val := random_string(nil, "16") + m.DeliveryStatus = omit.From(val) + } if !(m.Destination.IsValue()) { val := random_string(nil) m.Destination = omit.From(val) } + if !(m.PublicID.IsValue()) { + val := random_string(nil, "64") + m.PublicID = omit.From(val) + } if !(m.Source.IsValue()) { val := random_string(nil) m.Source = omit.From(val) } + if !(m.Subject.IsValue()) { + val := random_string(nil, "255") + m.Subject = omit.From(val) + } + if !(m.TemplateData.IsValue()) { + val := random_pgtypes_HStore(nil) + m.TemplateData = omit.From(val) + } if !(m.Type.IsValue()) { val := random_enums_CommsMessagetypeemail(nil) m.Type = omit.From(val) @@ -183,6 +258,25 @@ func ensureCreatableCommsEmailLog(m *models.CommsEmailLogSetter) { func (o *CommsEmailLogTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.CommsEmailLog) error { var err error + isTemplateEmailTemplateDone, _ := commsEmailLogRelTemplateEmailTemplateCtx.Value(ctx) + if !isTemplateEmailTemplateDone && o.r.TemplateEmailTemplate != nil { + ctx = commsEmailLogRelTemplateEmailTemplateCtx.WithValue(ctx, true) + if o.r.TemplateEmailTemplate.o.alreadyPersisted { + m.R.TemplateEmailTemplate = o.r.TemplateEmailTemplate.o.Build() + } else { + var rel1 *models.CommsEmailTemplate + rel1, err = o.r.TemplateEmailTemplate.o.Create(ctx, exec) + if err != nil { + return err + } + err = m.AttachTemplateEmailTemplate(ctx, exec, rel1) + if err != nil { + return err + } + } + + } + return err } @@ -193,16 +287,16 @@ func (o *CommsEmailLogTemplate) Create(ctx context.Context, exec bob.Executor) ( opt := o.BuildSetter() ensureCreatableCommsEmailLog(opt) - if o.r.DestinationEmail == nil { - CommsEmailLogMods.WithNewDestinationEmail().Apply(ctx, o) + if o.r.DestinationEmailContact == nil { + CommsEmailLogMods.WithNewDestinationEmailContact().Apply(ctx, o) } - var rel0 *models.CommsEmail + var rel0 *models.CommsEmailContact - if o.r.DestinationEmail.o.alreadyPersisted { - rel0 = o.r.DestinationEmail.o.Build() + if o.r.DestinationEmailContact.o.alreadyPersisted { + rel0 = o.r.DestinationEmailContact.o.Build() } else { - rel0, err = o.r.DestinationEmail.o.Create(ctx, exec) + rel0, err = o.r.DestinationEmailContact.o.Create(ctx, exec) if err != nil { return nil, err } @@ -210,30 +304,12 @@ func (o *CommsEmailLogTemplate) Create(ctx context.Context, exec bob.Executor) ( opt.Destination = omit.From(rel0.Address) - if o.r.SourcePhone == nil { - CommsEmailLogMods.WithNewSourcePhone().Apply(ctx, o) - } - - var rel1 *models.CommsPhone - - if o.r.SourcePhone.o.alreadyPersisted { - rel1 = o.r.SourcePhone.o.Build() - } else { - rel1, err = o.r.SourcePhone.o.Create(ctx, exec) - if err != nil { - return nil, err - } - } - - opt.Source = omit.From(rel1.E164) - m, err := models.CommsEmailLogs.Insert(opt).One(ctx, exec) if err != nil { return nil, err } - m.R.DestinationEmail = rel0 - m.R.SourcePhone = rel1 + m.R.DestinationEmailContact = rel0 if err := o.insertOptRels(ctx, exec, m); err != nil { return nil, err @@ -312,13 +388,51 @@ type commsEmailLogMods struct{} func (m commsEmailLogMods) RandomizeAllColumns(f *faker.Faker) CommsEmailLogMod { return CommsEmailLogModSlice{ + CommsEmailLogMods.RandomID(f), CommsEmailLogMods.RandomCreated(f), + CommsEmailLogMods.RandomDeliveryStatus(f), CommsEmailLogMods.RandomDestination(f), + CommsEmailLogMods.RandomPublicID(f), + CommsEmailLogMods.RandomSentAt(f), CommsEmailLogMods.RandomSource(f), + CommsEmailLogMods.RandomSubject(f), + CommsEmailLogMods.RandomTemplateID(f), + CommsEmailLogMods.RandomTemplateData(f), CommsEmailLogMods.RandomType(f), } } +// Set the model columns to this value +func (m commsEmailLogMods) ID(val int32) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.ID = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) IDFunc(f func() int32) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.ID = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetID() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.ID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailLogMods) RandomID(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.ID = func() int32 { + return random_int32(f) + } + }) +} + // Set the model columns to this value func (m commsEmailLogMods) Created(val time.Time) CommsEmailLogMod { return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { @@ -350,6 +464,37 @@ func (m commsEmailLogMods) RandomCreated(f *faker.Faker) CommsEmailLogMod { }) } +// Set the model columns to this value +func (m commsEmailLogMods) DeliveryStatus(val string) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.DeliveryStatus = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) DeliveryStatusFunc(f func() string) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.DeliveryStatus = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetDeliveryStatus() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.DeliveryStatus = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailLogMods) RandomDeliveryStatus(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.DeliveryStatus = func() string { + return random_string(f, "16") + } + }) +} + // Set the model columns to this value func (m commsEmailLogMods) Destination(val string) CommsEmailLogMod { return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { @@ -381,6 +526,90 @@ func (m commsEmailLogMods) RandomDestination(f *faker.Faker) CommsEmailLogMod { }) } +// Set the model columns to this value +func (m commsEmailLogMods) PublicID(val string) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.PublicID = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) PublicIDFunc(f func() string) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.PublicID = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetPublicID() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.PublicID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailLogMods) RandomPublicID(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.PublicID = func() string { + return random_string(f, "64") + } + }) +} + +// Set the model columns to this value +func (m commsEmailLogMods) SentAt(val null.Val[time.Time]) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.SentAt = func() null.Val[time.Time] { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) SentAtFunc(f func() null.Val[time.Time]) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.SentAt = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetSentAt() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.SentAt = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +// The generated value is sometimes null +func (m commsEmailLogMods) RandomSentAt(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.SentAt = func() null.Val[time.Time] { + if f == nil { + f = &defaultFaker + } + + val := random_time_Time(f) + return null.From(val) + } + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +// The generated value is never null +func (m commsEmailLogMods) RandomSentAtNotNull(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.SentAt = func() null.Val[time.Time] { + if f == nil { + f = &defaultFaker + } + + val := random_time_Time(f) + return null.From(val) + } + }) +} + // Set the model columns to this value func (m commsEmailLogMods) Source(val string) CommsEmailLogMod { return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { @@ -412,6 +641,121 @@ func (m commsEmailLogMods) RandomSource(f *faker.Faker) CommsEmailLogMod { }) } +// Set the model columns to this value +func (m commsEmailLogMods) Subject(val string) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.Subject = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) SubjectFunc(f func() string) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.Subject = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetSubject() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.Subject = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailLogMods) RandomSubject(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.Subject = func() string { + return random_string(f, "255") + } + }) +} + +// Set the model columns to this value +func (m commsEmailLogMods) TemplateID(val null.Val[int32]) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateID = func() null.Val[int32] { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) TemplateIDFunc(f func() null.Val[int32]) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateID = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetTemplateID() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +// The generated value is sometimes null +func (m commsEmailLogMods) RandomTemplateID(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateID = func() null.Val[int32] { + if f == nil { + f = &defaultFaker + } + + val := random_int32(f) + return null.From(val) + } + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +// The generated value is never null +func (m commsEmailLogMods) RandomTemplateIDNotNull(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateID = func() null.Val[int32] { + if f == nil { + f = &defaultFaker + } + + val := random_int32(f) + return null.From(val) + } + }) +} + +// Set the model columns to this value +func (m commsEmailLogMods) TemplateData(val pgtypes.HStore) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateData = func() pgtypes.HStore { return val } + }) +} + +// Set the Column from the function +func (m commsEmailLogMods) TemplateDataFunc(f func() pgtypes.HStore) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateData = f + }) +} + +// Clear any values for the column +func (m commsEmailLogMods) UnsetTemplateData() CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateData = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailLogMods) RandomTemplateData(f *faker.Faker) CommsEmailLogMod { + return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { + o.TemplateData = func() pgtypes.HStore { + return random_pgtypes_HStore(f) + } + }) +} + // Set the model columns to this value func (m commsEmailLogMods) Type(val enums.CommsMessagetypeemail) CommsEmailLogMod { return CommsEmailLogModFunc(func(_ context.Context, o *CommsEmailLogTemplate) { @@ -451,73 +795,73 @@ func (m commsEmailLogMods) WithParentsCascading() CommsEmailLogMod { ctx = commsEmailLogWithParentsCascadingCtx.WithValue(ctx, true) { - related := o.f.NewCommsEmailWithContext(ctx, CommsEmailMods.WithParentsCascading()) - m.WithDestinationEmail(related).Apply(ctx, o) + related := o.f.NewCommsEmailContactWithContext(ctx, CommsEmailContactMods.WithParentsCascading()) + m.WithDestinationEmailContact(related).Apply(ctx, o) } { - related := o.f.NewCommsPhoneWithContext(ctx, CommsPhoneMods.WithParentsCascading()) - m.WithSourcePhone(related).Apply(ctx, o) + related := o.f.NewCommsEmailTemplateWithContext(ctx, CommsEmailTemplateMods.WithParentsCascading()) + m.WithTemplateEmailTemplate(related).Apply(ctx, o) } }) } -func (m commsEmailLogMods) WithDestinationEmail(rel *CommsEmailTemplate) CommsEmailLogMod { +func (m commsEmailLogMods) WithDestinationEmailContact(rel *CommsEmailContactTemplate) CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - o.r.DestinationEmail = &commsEmailLogRDestinationEmailR{ + o.r.DestinationEmailContact = &commsEmailLogRDestinationEmailContactR{ o: rel, } }) } -func (m commsEmailLogMods) WithNewDestinationEmail(mods ...CommsEmailMod) CommsEmailLogMod { +func (m commsEmailLogMods) WithNewDestinationEmailContact(mods ...CommsEmailContactMod) CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - related := o.f.NewCommsEmailWithContext(ctx, mods...) + related := o.f.NewCommsEmailContactWithContext(ctx, mods...) - m.WithDestinationEmail(related).Apply(ctx, o) + m.WithDestinationEmailContact(related).Apply(ctx, o) }) } -func (m commsEmailLogMods) WithExistingDestinationEmail(em *models.CommsEmail) CommsEmailLogMod { +func (m commsEmailLogMods) WithExistingDestinationEmailContact(em *models.CommsEmailContact) CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - o.r.DestinationEmail = &commsEmailLogRDestinationEmailR{ - o: o.f.FromExistingCommsEmail(em), + o.r.DestinationEmailContact = &commsEmailLogRDestinationEmailContactR{ + o: o.f.FromExistingCommsEmailContact(em), } }) } -func (m commsEmailLogMods) WithoutDestinationEmail() CommsEmailLogMod { +func (m commsEmailLogMods) WithoutDestinationEmailContact() CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - o.r.DestinationEmail = nil + o.r.DestinationEmailContact = nil }) } -func (m commsEmailLogMods) WithSourcePhone(rel *CommsPhoneTemplate) CommsEmailLogMod { +func (m commsEmailLogMods) WithTemplateEmailTemplate(rel *CommsEmailTemplateTemplate) CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - o.r.SourcePhone = &commsEmailLogRSourcePhoneR{ + o.r.TemplateEmailTemplate = &commsEmailLogRTemplateEmailTemplateR{ o: rel, } }) } -func (m commsEmailLogMods) WithNewSourcePhone(mods ...CommsPhoneMod) CommsEmailLogMod { +func (m commsEmailLogMods) WithNewTemplateEmailTemplate(mods ...CommsEmailTemplateMod) CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - related := o.f.NewCommsPhoneWithContext(ctx, mods...) + related := o.f.NewCommsEmailTemplateWithContext(ctx, mods...) - m.WithSourcePhone(related).Apply(ctx, o) + m.WithTemplateEmailTemplate(related).Apply(ctx, o) }) } -func (m commsEmailLogMods) WithExistingSourcePhone(em *models.CommsPhone) CommsEmailLogMod { +func (m commsEmailLogMods) WithExistingTemplateEmailTemplate(em *models.CommsEmailTemplate) CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - o.r.SourcePhone = &commsEmailLogRSourcePhoneR{ - o: o.f.FromExistingCommsPhone(em), + o.r.TemplateEmailTemplate = &commsEmailLogRTemplateEmailTemplateR{ + o: o.f.FromExistingCommsEmailTemplate(em), } }) } -func (m commsEmailLogMods) WithoutSourcePhone() CommsEmailLogMod { +func (m commsEmailLogMods) WithoutTemplateEmailTemplate() CommsEmailLogMod { return CommsEmailLogModFunc(func(ctx context.Context, o *CommsEmailLogTemplate) { - o.r.SourcePhone = nil + o.r.TemplateEmailTemplate = nil }) } diff --git a/db/factory/comms.email_template.bob.go b/db/factory/comms.email_template.bob.go new file mode 100644 index 00000000..dbfdd1f7 --- /dev/null +++ b/db/factory/comms.email_template.bob.go @@ -0,0 +1,672 @@ +// Code generated by BobGen psql v0.42.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package factory + +import ( + "context" + "testing" + "time" + + enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" + models "github.com/Gleipnir-Technology/nidus-sync/db/models" + "github.com/aarondl/opt/null" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/jaswdr/faker/v2" + "github.com/stephenafamo/bob" +) + +type CommsEmailTemplateMod interface { + Apply(context.Context, *CommsEmailTemplateTemplate) +} + +type CommsEmailTemplateModFunc func(context.Context, *CommsEmailTemplateTemplate) + +func (f CommsEmailTemplateModFunc) Apply(ctx context.Context, n *CommsEmailTemplateTemplate) { + f(ctx, n) +} + +type CommsEmailTemplateModSlice []CommsEmailTemplateMod + +func (mods CommsEmailTemplateModSlice) Apply(ctx context.Context, n *CommsEmailTemplateTemplate) { + for _, f := range mods { + f.Apply(ctx, n) + } +} + +// CommsEmailTemplateTemplate is an object representing the database table. +// all columns are optional and should be set by mods +type CommsEmailTemplateTemplate struct { + ContentHTML func() string + ContentTXT func() string + ContentHashHTML func() string + ContentHashTXT func() string + Created func() time.Time + ID func() int32 + Superceded func() null.Val[time.Time] + MessageType func() enums.CommsMessagetypeemail + + r commsEmailTemplateR + f *Factory + + alreadyPersisted bool +} + +type commsEmailTemplateR struct { + TemplateEmailLogs []*commsEmailTemplateRTemplateEmailLogsR +} + +type commsEmailTemplateRTemplateEmailLogsR struct { + number int + o *CommsEmailLogTemplate +} + +// Apply mods to the CommsEmailTemplateTemplate +func (o *CommsEmailTemplateTemplate) Apply(ctx context.Context, mods ...CommsEmailTemplateMod) { + for _, mod := range mods { + mod.Apply(ctx, o) + } +} + +// setModelRels creates and sets the relationships on *models.CommsEmailTemplate +// according to the relationships in the template. Nothing is inserted into the db +func (t CommsEmailTemplateTemplate) setModelRels(o *models.CommsEmailTemplate) { + if t.r.TemplateEmailLogs != nil { + rel := models.CommsEmailLogSlice{} + for _, r := range t.r.TemplateEmailLogs { + related := r.o.BuildMany(r.number) + for _, rel := range related { + rel.TemplateID = null.From(o.ID) // h2 + rel.R.TemplateEmailTemplate = o + } + rel = append(rel, related...) + } + o.R.TemplateEmailLogs = rel + } +} + +// BuildSetter returns an *models.CommsEmailTemplateSetter +// this does nothing with the relationship templates +func (o CommsEmailTemplateTemplate) BuildSetter() *models.CommsEmailTemplateSetter { + m := &models.CommsEmailTemplateSetter{} + + if o.ContentHTML != nil { + val := o.ContentHTML() + m.ContentHTML = omit.From(val) + } + if o.ContentTXT != nil { + val := o.ContentTXT() + m.ContentTXT = omit.From(val) + } + if o.ContentHashHTML != nil { + val := o.ContentHashHTML() + m.ContentHashHTML = omit.From(val) + } + if o.ContentHashTXT != nil { + val := o.ContentHashTXT() + m.ContentHashTXT = omit.From(val) + } + if o.Created != nil { + val := o.Created() + m.Created = omit.From(val) + } + if o.ID != nil { + val := o.ID() + m.ID = omit.From(val) + } + if o.Superceded != nil { + val := o.Superceded() + m.Superceded = omitnull.FromNull(val) + } + if o.MessageType != nil { + val := o.MessageType() + m.MessageType = omit.From(val) + } + + return m +} + +// BuildManySetter returns an []*models.CommsEmailTemplateSetter +// this does nothing with the relationship templates +func (o CommsEmailTemplateTemplate) BuildManySetter(number int) []*models.CommsEmailTemplateSetter { + m := make([]*models.CommsEmailTemplateSetter, number) + + for i := range m { + m[i] = o.BuildSetter() + } + + return m +} + +// Build returns an *models.CommsEmailTemplate +// Related objects are also created and placed in the .R field +// NOTE: Objects are not inserted into the database. Use CommsEmailTemplateTemplate.Create +func (o CommsEmailTemplateTemplate) Build() *models.CommsEmailTemplate { + m := &models.CommsEmailTemplate{} + + if o.ContentHTML != nil { + m.ContentHTML = o.ContentHTML() + } + if o.ContentTXT != nil { + m.ContentTXT = o.ContentTXT() + } + if o.ContentHashHTML != nil { + m.ContentHashHTML = o.ContentHashHTML() + } + if o.ContentHashTXT != nil { + m.ContentHashTXT = o.ContentHashTXT() + } + if o.Created != nil { + m.Created = o.Created() + } + if o.ID != nil { + m.ID = o.ID() + } + if o.Superceded != nil { + m.Superceded = o.Superceded() + } + if o.MessageType != nil { + m.MessageType = o.MessageType() + } + + o.setModelRels(m) + + return m +} + +// BuildMany returns an models.CommsEmailTemplateSlice +// Related objects are also created and placed in the .R field +// NOTE: Objects are not inserted into the database. Use CommsEmailTemplateTemplate.CreateMany +func (o CommsEmailTemplateTemplate) BuildMany(number int) models.CommsEmailTemplateSlice { + m := make(models.CommsEmailTemplateSlice, number) + + for i := range m { + m[i] = o.Build() + } + + return m +} + +func ensureCreatableCommsEmailTemplate(m *models.CommsEmailTemplateSetter) { + if !(m.ContentHTML.IsValue()) { + val := random_string(nil) + m.ContentHTML = omit.From(val) + } + if !(m.ContentTXT.IsValue()) { + val := random_string(nil) + m.ContentTXT = omit.From(val) + } + if !(m.ContentHashHTML.IsValue()) { + val := random_string(nil, "64") + m.ContentHashHTML = omit.From(val) + } + if !(m.ContentHashTXT.IsValue()) { + val := random_string(nil, "64") + m.ContentHashTXT = omit.From(val) + } + if !(m.Created.IsValue()) { + val := random_time_Time(nil) + m.Created = omit.From(val) + } + if !(m.MessageType.IsValue()) { + val := random_enums_CommsMessagetypeemail(nil) + m.MessageType = omit.From(val) + } +} + +// insertOptRels creates and inserts any optional the relationships on *models.CommsEmailTemplate +// according to the relationships in the template. +// any required relationship should have already exist on the model +func (o *CommsEmailTemplateTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.CommsEmailTemplate) error { + var err error + + isTemplateEmailLogsDone, _ := commsEmailTemplateRelTemplateEmailLogsCtx.Value(ctx) + if !isTemplateEmailLogsDone && o.r.TemplateEmailLogs != nil { + ctx = commsEmailTemplateRelTemplateEmailLogsCtx.WithValue(ctx, true) + for _, r := range o.r.TemplateEmailLogs { + if r.o.alreadyPersisted { + m.R.TemplateEmailLogs = append(m.R.TemplateEmailLogs, r.o.Build()) + } else { + rel0, err := r.o.CreateMany(ctx, exec, r.number) + if err != nil { + return err + } + + err = m.AttachTemplateEmailLogs(ctx, exec, rel0...) + if err != nil { + return err + } + } + } + } + + return err +} + +// Create builds a commsEmailTemplate and inserts it into the database +// Relations objects are also inserted and placed in the .R field +func (o *CommsEmailTemplateTemplate) Create(ctx context.Context, exec bob.Executor) (*models.CommsEmailTemplate, error) { + var err error + opt := o.BuildSetter() + ensureCreatableCommsEmailTemplate(opt) + + m, err := models.CommsEmailTemplates.Insert(opt).One(ctx, exec) + if err != nil { + return nil, err + } + + if err := o.insertOptRels(ctx, exec, m); err != nil { + return nil, err + } + return m, err +} + +// MustCreate builds a commsEmailTemplate and inserts it into the database +// Relations objects are also inserted and placed in the .R field +// panics if an error occurs +func (o *CommsEmailTemplateTemplate) MustCreate(ctx context.Context, exec bob.Executor) *models.CommsEmailTemplate { + m, err := o.Create(ctx, exec) + if err != nil { + panic(err) + } + return m +} + +// CreateOrFail builds a commsEmailTemplate and inserts it into the database +// Relations objects are also inserted and placed in the .R field +// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs +func (o *CommsEmailTemplateTemplate) CreateOrFail(ctx context.Context, tb testing.TB, exec bob.Executor) *models.CommsEmailTemplate { + tb.Helper() + m, err := o.Create(ctx, exec) + if err != nil { + tb.Fatal(err) + return nil + } + return m +} + +// CreateMany builds multiple commsEmailTemplates and inserts them into the database +// Relations objects are also inserted and placed in the .R field +func (o CommsEmailTemplateTemplate) CreateMany(ctx context.Context, exec bob.Executor, number int) (models.CommsEmailTemplateSlice, error) { + var err error + m := make(models.CommsEmailTemplateSlice, number) + + for i := range m { + m[i], err = o.Create(ctx, exec) + if err != nil { + return nil, err + } + } + + return m, nil +} + +// MustCreateMany builds multiple commsEmailTemplates and inserts them into the database +// Relations objects are also inserted and placed in the .R field +// panics if an error occurs +func (o CommsEmailTemplateTemplate) MustCreateMany(ctx context.Context, exec bob.Executor, number int) models.CommsEmailTemplateSlice { + m, err := o.CreateMany(ctx, exec, number) + if err != nil { + panic(err) + } + return m +} + +// CreateManyOrFail builds multiple commsEmailTemplates and inserts them into the database +// Relations objects are also inserted and placed in the .R field +// It calls `tb.Fatal(err)` on the test/benchmark if an error occurs +func (o CommsEmailTemplateTemplate) CreateManyOrFail(ctx context.Context, tb testing.TB, exec bob.Executor, number int) models.CommsEmailTemplateSlice { + tb.Helper() + m, err := o.CreateMany(ctx, exec, number) + if err != nil { + tb.Fatal(err) + return nil + } + return m +} + +// CommsEmailTemplate has methods that act as mods for the CommsEmailTemplateTemplate +var CommsEmailTemplateMods commsEmailTemplateMods + +type commsEmailTemplateMods struct{} + +func (m commsEmailTemplateMods) RandomizeAllColumns(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModSlice{ + CommsEmailTemplateMods.RandomContentHTML(f), + CommsEmailTemplateMods.RandomContentTXT(f), + CommsEmailTemplateMods.RandomContentHashHTML(f), + CommsEmailTemplateMods.RandomContentHashTXT(f), + CommsEmailTemplateMods.RandomCreated(f), + CommsEmailTemplateMods.RandomID(f), + CommsEmailTemplateMods.RandomSuperceded(f), + CommsEmailTemplateMods.RandomMessageType(f), + } +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) ContentHTML(val string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHTML = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) ContentHTMLFunc(f func() string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHTML = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetContentHTML() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHTML = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomContentHTML(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHTML = func() string { + return random_string(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) ContentTXT(val string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentTXT = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) ContentTXTFunc(f func() string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentTXT = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetContentTXT() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentTXT = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomContentTXT(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentTXT = func() string { + return random_string(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) ContentHashHTML(val string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashHTML = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) ContentHashHTMLFunc(f func() string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashHTML = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetContentHashHTML() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashHTML = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomContentHashHTML(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashHTML = func() string { + return random_string(f, "64") + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) ContentHashTXT(val string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashTXT = func() string { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) ContentHashTXTFunc(f func() string) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashTXT = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetContentHashTXT() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashTXT = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomContentHashTXT(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ContentHashTXT = func() string { + return random_string(f, "64") + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) Created(val time.Time) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Created = func() time.Time { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) CreatedFunc(f func() time.Time) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Created = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetCreated() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Created = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomCreated(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Created = func() time.Time { + return random_time_Time(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) ID(val int32) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ID = func() int32 { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) IDFunc(f func() int32) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ID = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetID() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ID = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomID(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.ID = func() int32 { + return random_int32(f) + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) Superceded(val null.Val[time.Time]) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Superceded = func() null.Val[time.Time] { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) SupercededFunc(f func() null.Val[time.Time]) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Superceded = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetSuperceded() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Superceded = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +// The generated value is sometimes null +func (m commsEmailTemplateMods) RandomSuperceded(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Superceded = func() null.Val[time.Time] { + if f == nil { + f = &defaultFaker + } + + val := random_time_Time(f) + return null.From(val) + } + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +// The generated value is never null +func (m commsEmailTemplateMods) RandomSupercededNotNull(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.Superceded = func() null.Val[time.Time] { + if f == nil { + f = &defaultFaker + } + + val := random_time_Time(f) + return null.From(val) + } + }) +} + +// Set the model columns to this value +func (m commsEmailTemplateMods) MessageType(val enums.CommsMessagetypeemail) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.MessageType = func() enums.CommsMessagetypeemail { return val } + }) +} + +// Set the Column from the function +func (m commsEmailTemplateMods) MessageTypeFunc(f func() enums.CommsMessagetypeemail) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.MessageType = f + }) +} + +// Clear any values for the column +func (m commsEmailTemplateMods) UnsetMessageType() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.MessageType = nil + }) +} + +// Generates a random value for the column using the given faker +// if faker is nil, a default faker is used +func (m commsEmailTemplateMods) RandomMessageType(f *faker.Faker) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(_ context.Context, o *CommsEmailTemplateTemplate) { + o.MessageType = func() enums.CommsMessagetypeemail { + return random_enums_CommsMessagetypeemail(f) + } + }) +} + +func (m commsEmailTemplateMods) WithParentsCascading() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + if isDone, _ := commsEmailTemplateWithParentsCascadingCtx.Value(ctx); isDone { + return + } + ctx = commsEmailTemplateWithParentsCascadingCtx.WithValue(ctx, true) + }) +} + +func (m commsEmailTemplateMods) WithTemplateEmailLogs(number int, related *CommsEmailLogTemplate) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + o.r.TemplateEmailLogs = []*commsEmailTemplateRTemplateEmailLogsR{{ + number: number, + o: related, + }} + }) +} + +func (m commsEmailTemplateMods) WithNewTemplateEmailLogs(number int, mods ...CommsEmailLogMod) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + related := o.f.NewCommsEmailLogWithContext(ctx, mods...) + m.WithTemplateEmailLogs(number, related).Apply(ctx, o) + }) +} + +func (m commsEmailTemplateMods) AddTemplateEmailLogs(number int, related *CommsEmailLogTemplate) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + o.r.TemplateEmailLogs = append(o.r.TemplateEmailLogs, &commsEmailTemplateRTemplateEmailLogsR{ + number: number, + o: related, + }) + }) +} + +func (m commsEmailTemplateMods) AddNewTemplateEmailLogs(number int, mods ...CommsEmailLogMod) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + related := o.f.NewCommsEmailLogWithContext(ctx, mods...) + m.AddTemplateEmailLogs(number, related).Apply(ctx, o) + }) +} + +func (m commsEmailTemplateMods) AddExistingTemplateEmailLogs(existingModels ...*models.CommsEmailLog) CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + for _, em := range existingModels { + o.r.TemplateEmailLogs = append(o.r.TemplateEmailLogs, &commsEmailTemplateRTemplateEmailLogsR{ + o: o.f.FromExistingCommsEmailLog(em), + }) + } + }) +} + +func (m commsEmailTemplateMods) WithoutTemplateEmailLogs() CommsEmailTemplateMod { + return CommsEmailTemplateModFunc(func(ctx context.Context, o *CommsEmailTemplateTemplate) { + o.r.TemplateEmailLogs = nil + }) +} diff --git a/db/factory/comms.phone.bob.go b/db/factory/comms.phone.bob.go index 26b8eabf..415c6957 100644 --- a/db/factory/comms.phone.bob.go +++ b/db/factory/comms.phone.bob.go @@ -44,15 +44,10 @@ type CommsPhoneTemplate struct { } type commsPhoneR struct { - SourceEmailLogs []*commsPhoneRSourceEmailLogsR DestinationTextLogs []*commsPhoneRDestinationTextLogsR SourceTextLogs []*commsPhoneRSourceTextLogsR } -type commsPhoneRSourceEmailLogsR struct { - number int - o *CommsEmailLogTemplate -} type commsPhoneRDestinationTextLogsR struct { number int o *CommsTextLogTemplate @@ -72,19 +67,6 @@ func (o *CommsPhoneTemplate) Apply(ctx context.Context, mods ...CommsPhoneMod) { // setModelRels creates and sets the relationships on *models.CommsPhone // according to the relationships in the template. Nothing is inserted into the db func (t CommsPhoneTemplate) setModelRels(o *models.CommsPhone) { - if t.r.SourceEmailLogs != nil { - rel := models.CommsEmailLogSlice{} - for _, r := range t.r.SourceEmailLogs { - related := r.o.BuildMany(r.number) - for _, rel := range related { - rel.Source = o.E164 // h2 - rel.R.SourcePhone = o - } - rel = append(rel, related...) - } - o.R.SourceEmailLogs = rel - } - if t.r.DestinationTextLogs != nil { rel := models.CommsTextLogSlice{} for _, r := range t.r.DestinationTextLogs { @@ -189,26 +171,6 @@ func ensureCreatableCommsPhone(m *models.CommsPhoneSetter) { func (o *CommsPhoneTemplate) insertOptRels(ctx context.Context, exec bob.Executor, m *models.CommsPhone) error { var err error - isSourceEmailLogsDone, _ := commsPhoneRelSourceEmailLogsCtx.Value(ctx) - if !isSourceEmailLogsDone && o.r.SourceEmailLogs != nil { - ctx = commsPhoneRelSourceEmailLogsCtx.WithValue(ctx, true) - for _, r := range o.r.SourceEmailLogs { - if r.o.alreadyPersisted { - m.R.SourceEmailLogs = append(m.R.SourceEmailLogs, r.o.Build()) - } else { - rel0, err := r.o.CreateMany(ctx, exec, r.number) - if err != nil { - return err - } - - err = m.AttachSourceEmailLogs(ctx, exec, rel0...) - if err != nil { - return err - } - } - } - } - isDestinationTextLogsDone, _ := commsPhoneRelDestinationTextLogsCtx.Value(ctx) if !isDestinationTextLogsDone && o.r.DestinationTextLogs != nil { ctx = commsPhoneRelDestinationTextLogsCtx.WithValue(ctx, true) @@ -216,12 +178,12 @@ func (o *CommsPhoneTemplate) insertOptRels(ctx context.Context, exec bob.Executo if r.o.alreadyPersisted { m.R.DestinationTextLogs = append(m.R.DestinationTextLogs, r.o.Build()) } else { - rel1, err := r.o.CreateMany(ctx, exec, r.number) + rel0, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachDestinationTextLogs(ctx, exec, rel1...) + err = m.AttachDestinationTextLogs(ctx, exec, rel0...) if err != nil { return err } @@ -236,12 +198,12 @@ func (o *CommsPhoneTemplate) insertOptRels(ctx context.Context, exec bob.Executo if r.o.alreadyPersisted { m.R.SourceTextLogs = append(m.R.SourceTextLogs, r.o.Build()) } else { - rel2, err := r.o.CreateMany(ctx, exec, r.number) + rel1, err := r.o.CreateMany(ctx, exec, r.number) if err != nil { return err } - err = m.AttachSourceTextLogs(ctx, exec, rel2...) + err = m.AttachSourceTextLogs(ctx, exec, rel1...) if err != nil { return err } @@ -417,54 +379,6 @@ func (m commsPhoneMods) WithParentsCascading() CommsPhoneMod { }) } -func (m commsPhoneMods) WithSourceEmailLogs(number int, related *CommsEmailLogTemplate) CommsPhoneMod { - return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { - o.r.SourceEmailLogs = []*commsPhoneRSourceEmailLogsR{{ - number: number, - o: related, - }} - }) -} - -func (m commsPhoneMods) WithNewSourceEmailLogs(number int, mods ...CommsEmailLogMod) CommsPhoneMod { - return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { - related := o.f.NewCommsEmailLogWithContext(ctx, mods...) - m.WithSourceEmailLogs(number, related).Apply(ctx, o) - }) -} - -func (m commsPhoneMods) AddSourceEmailLogs(number int, related *CommsEmailLogTemplate) CommsPhoneMod { - return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { - o.r.SourceEmailLogs = append(o.r.SourceEmailLogs, &commsPhoneRSourceEmailLogsR{ - number: number, - o: related, - }) - }) -} - -func (m commsPhoneMods) AddNewSourceEmailLogs(number int, mods ...CommsEmailLogMod) CommsPhoneMod { - return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { - related := o.f.NewCommsEmailLogWithContext(ctx, mods...) - m.AddSourceEmailLogs(number, related).Apply(ctx, o) - }) -} - -func (m commsPhoneMods) AddExistingSourceEmailLogs(existingModels ...*models.CommsEmailLog) CommsPhoneMod { - return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { - for _, em := range existingModels { - o.r.SourceEmailLogs = append(o.r.SourceEmailLogs, &commsPhoneRSourceEmailLogsR{ - o: o.f.FromExistingCommsEmailLog(em), - }) - } - }) -} - -func (m commsPhoneMods) WithoutSourceEmailLogs() CommsPhoneMod { - return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { - o.r.SourceEmailLogs = nil - }) -} - func (m commsPhoneMods) WithDestinationTextLogs(number int, related *CommsTextLogTemplate) CommsPhoneMod { return CommsPhoneModFunc(func(ctx context.Context, o *CommsPhoneTemplate) { o.r.DestinationTextLogs = []*commsPhoneRDestinationTextLogsR{{ diff --git a/db/migrations/00039_email_template.sql b/db/migrations/00039_email_template.sql new file mode 100644 index 00000000..ba42ffbe --- /dev/null +++ b/db/migrations/00039_email_template.sql @@ -0,0 +1,44 @@ +-- +goose Up +-- CREATE EXTENSION IF NOT EXISTS hstore; +ALTER TABLE comms.email RENAME TO email_contact; +ALTER TABLE comms.email_contact ADD COLUMN public_id TEXT; +UPDATE comms.email_contact SET public_id = ''; +ALTER TABLE comms.email_contact ALTER COLUMN public_id SET NOT NULL; +CREATE TABLE comms.email_template ( + content_html TEXT NOT NULL, + content_txt TEXT NOT NULL, + content_hash_html VARCHAR(64) NOT NULL, + content_hash_txt VARCHAR(64) NOT NULL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + id SERIAL NOT NULL, + superceded TIMESTAMP WITHOUT TIME ZONE, + message_type comms.MessageTypeEmail NOT NULL, + PRIMARY KEY (id) +); +DROP TABLE comms.email_log; +CREATE TABLE comms.email_log ( + id SERIAL, + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + delivery_status VARCHAR(16) NOT NULL, + destination TEXT NOT NULL REFERENCES comms.email_contact(address), + public_id VARCHAR(64) NOT NULL, + sent_at TIMESTAMP WITHOUT TIME ZONE, + source TEXT NOT NULL, + subject VARCHAR(255) NOT NULL, + template_id INTEGER REFERENCES comms.email_template(id), + template_data HSTORE NOT NULL, + type comms.MessageTypeEmail NOT NULL, + PRIMARY KEY (id) +); +-- +goose Down +DROP TABLE comms.email_log; +CREATE TABLE comms.email_log ( + created TIMESTAMP WITHOUT TIME ZONE NOT NULL, + destination TEXT NOT NULL REFERENCES comms.email_contact(address), + source TEXT NOT NULL REFERENCES comms.phone(e164), + type comms.MessageTypeEmail NOT NULL, + PRIMARY KEY(destination, source, type) +); +DROP TABLE comms.email_template; +ALTER TABLE comms.email_contact DROP COLUMN public_id; +ALTER TABLE comms.email_contact RENAME TO email; diff --git a/db/models/bob_counts.bob.go b/db/models/bob_counts.bob.go index 2deaf5bb..41648f3a 100644 --- a/db/models/bob_counts.bob.go +++ b/db/models/bob_counts.bob.go @@ -21,58 +21,62 @@ var ( ) type preloadCounts struct { - ArcgisUser arcgisuserCountPreloader - CommsEmail commsEmailCountPreloader - CommsPhone commsPhoneCountPreloader - NoteAudio noteAudioCountPreloader - NoteImage noteImageCountPreloader - Organization organizationCountPreloader - PublicreportImage publicreportImageCountPreloader - PublicreportPool publicreportPoolCountPreloader - PublicreportQuick publicreportQuickCountPreloader - User userCountPreloader + ArcgisUser arcgisuserCountPreloader + CommsEmailContact commsEmailContactCountPreloader + CommsEmailTemplate commsEmailTemplateCountPreloader + CommsPhone commsPhoneCountPreloader + NoteAudio noteAudioCountPreloader + NoteImage noteImageCountPreloader + Organization organizationCountPreloader + PublicreportImage publicreportImageCountPreloader + PublicreportPool publicreportPoolCountPreloader + PublicreportQuick publicreportQuickCountPreloader + User userCountPreloader } func getPreloadCount() preloadCounts { return preloadCounts{ - ArcgisUser: buildArcgisUserCountPreloader(), - CommsEmail: buildCommsEmailCountPreloader(), - CommsPhone: buildCommsPhoneCountPreloader(), - NoteAudio: buildNoteAudioCountPreloader(), - NoteImage: buildNoteImageCountPreloader(), - Organization: buildOrganizationCountPreloader(), - PublicreportImage: buildPublicreportImageCountPreloader(), - PublicreportPool: buildPublicreportPoolCountPreloader(), - PublicreportQuick: buildPublicreportQuickCountPreloader(), - User: buildUserCountPreloader(), + ArcgisUser: buildArcgisUserCountPreloader(), + CommsEmailContact: buildCommsEmailContactCountPreloader(), + CommsEmailTemplate: buildCommsEmailTemplateCountPreloader(), + CommsPhone: buildCommsPhoneCountPreloader(), + NoteAudio: buildNoteAudioCountPreloader(), + NoteImage: buildNoteImageCountPreloader(), + Organization: buildOrganizationCountPreloader(), + PublicreportImage: buildPublicreportImageCountPreloader(), + PublicreportPool: buildPublicreportPoolCountPreloader(), + PublicreportQuick: buildPublicreportQuickCountPreloader(), + User: buildUserCountPreloader(), } } type thenLoadCounts[Q orm.Loadable] struct { - ArcgisUser arcgisuserCountThenLoader[Q] - CommsEmail commsEmailCountThenLoader[Q] - CommsPhone commsPhoneCountThenLoader[Q] - NoteAudio noteAudioCountThenLoader[Q] - NoteImage noteImageCountThenLoader[Q] - Organization organizationCountThenLoader[Q] - PublicreportImage publicreportImageCountThenLoader[Q] - PublicreportPool publicreportPoolCountThenLoader[Q] - PublicreportQuick publicreportQuickCountThenLoader[Q] - User userCountThenLoader[Q] + ArcgisUser arcgisuserCountThenLoader[Q] + CommsEmailContact commsEmailContactCountThenLoader[Q] + CommsEmailTemplate commsEmailTemplateCountThenLoader[Q] + CommsPhone commsPhoneCountThenLoader[Q] + NoteAudio noteAudioCountThenLoader[Q] + NoteImage noteImageCountThenLoader[Q] + Organization organizationCountThenLoader[Q] + PublicreportImage publicreportImageCountThenLoader[Q] + PublicreportPool publicreportPoolCountThenLoader[Q] + PublicreportQuick publicreportQuickCountThenLoader[Q] + User userCountThenLoader[Q] } func getThenLoadCount[Q orm.Loadable]() thenLoadCounts[Q] { return thenLoadCounts[Q]{ - ArcgisUser: buildArcgisUserCountThenLoader[Q](), - CommsEmail: buildCommsEmailCountThenLoader[Q](), - CommsPhone: buildCommsPhoneCountThenLoader[Q](), - NoteAudio: buildNoteAudioCountThenLoader[Q](), - NoteImage: buildNoteImageCountThenLoader[Q](), - Organization: buildOrganizationCountThenLoader[Q](), - PublicreportImage: buildPublicreportImageCountThenLoader[Q](), - PublicreportPool: buildPublicreportPoolCountThenLoader[Q](), - PublicreportQuick: buildPublicreportQuickCountThenLoader[Q](), - User: buildUserCountThenLoader[Q](), + ArcgisUser: buildArcgisUserCountThenLoader[Q](), + CommsEmailContact: buildCommsEmailContactCountThenLoader[Q](), + CommsEmailTemplate: buildCommsEmailTemplateCountThenLoader[Q](), + CommsPhone: buildCommsPhoneCountThenLoader[Q](), + NoteAudio: buildNoteAudioCountThenLoader[Q](), + NoteImage: buildNoteImageCountThenLoader[Q](), + Organization: buildOrganizationCountThenLoader[Q](), + PublicreportImage: buildPublicreportImageCountThenLoader[Q](), + PublicreportPool: buildPublicreportPoolCountThenLoader[Q](), + PublicreportQuick: buildPublicreportQuickCountThenLoader[Q](), + User: buildUserCountThenLoader[Q](), } } diff --git a/db/models/bob_joins.bob.go b/db/models/bob_joins.bob.go index 4455b426..e6ca18af 100644 --- a/db/models/bob_joins.bob.go +++ b/db/models/bob_joins.bob.go @@ -34,8 +34,9 @@ func (j joinSet[Q]) AliasedAs(alias string) joinSet[Q] { type joins[Q dialect.Joinable] struct { ArcgisUsers joinSet[arcgisuserJoins[Q]] ArcgisUserPrivileges joinSet[arcgisUserPrivilegeJoins[Q]] - CommsEmails joinSet[commsEmailJoins[Q]] + CommsEmailContacts joinSet[commsEmailContactJoins[Q]] CommsEmailLogs joinSet[commsEmailLogJoins[Q]] + CommsEmailTemplates joinSet[commsEmailTemplateJoins[Q]] CommsPhones joinSet[commsPhoneJoins[Q]] CommsTextLogs joinSet[commsTextLogJoins[Q]] FieldseekerContainerrelates joinSet[fieldseekerContainerrelateJoins[Q]] @@ -99,8 +100,9 @@ func getJoins[Q dialect.Joinable]() joins[Q] { return joins[Q]{ ArcgisUsers: buildJoinSet[arcgisuserJoins[Q]](ArcgisUsers.Columns, buildArcgisUserJoins), ArcgisUserPrivileges: buildJoinSet[arcgisUserPrivilegeJoins[Q]](ArcgisUserPrivileges.Columns, buildArcgisUserPrivilegeJoins), - CommsEmails: buildJoinSet[commsEmailJoins[Q]](CommsEmails.Columns, buildCommsEmailJoins), + CommsEmailContacts: buildJoinSet[commsEmailContactJoins[Q]](CommsEmailContacts.Columns, buildCommsEmailContactJoins), CommsEmailLogs: buildJoinSet[commsEmailLogJoins[Q]](CommsEmailLogs.Columns, buildCommsEmailLogJoins), + CommsEmailTemplates: buildJoinSet[commsEmailTemplateJoins[Q]](CommsEmailTemplates.Columns, buildCommsEmailTemplateJoins), CommsPhones: buildJoinSet[commsPhoneJoins[Q]](CommsPhones.Columns, buildCommsPhoneJoins), CommsTextLogs: buildJoinSet[commsTextLogJoins[Q]](CommsTextLogs.Columns, buildCommsTextLogJoins), FieldseekerContainerrelates: buildJoinSet[fieldseekerContainerrelateJoins[Q]](FieldseekerContainerrelates.Columns, buildFieldseekerContainerrelateJoins), diff --git a/db/models/bob_loaders.bob.go b/db/models/bob_loaders.bob.go index 1b3475de..aff45d78 100644 --- a/db/models/bob_loaders.bob.go +++ b/db/models/bob_loaders.bob.go @@ -19,8 +19,9 @@ var Preload = getPreloaders() type preloaders struct { ArcgisUser arcgisuserPreloader ArcgisUserPrivilege arcgisUserPrivilegePreloader - CommsEmail commsEmailPreloader + CommsEmailContact commsEmailContactPreloader CommsEmailLog commsEmailLogPreloader + CommsEmailTemplate commsEmailTemplatePreloader CommsPhone commsPhonePreloader CommsTextLog commsTextLogPreloader FieldseekerContainerrelate fieldseekerContainerrelatePreloader @@ -76,8 +77,9 @@ func getPreloaders() preloaders { return preloaders{ ArcgisUser: buildArcgisUserPreloader(), ArcgisUserPrivilege: buildArcgisUserPrivilegePreloader(), - CommsEmail: buildCommsEmailPreloader(), + CommsEmailContact: buildCommsEmailContactPreloader(), CommsEmailLog: buildCommsEmailLogPreloader(), + CommsEmailTemplate: buildCommsEmailTemplatePreloader(), CommsPhone: buildCommsPhonePreloader(), CommsTextLog: buildCommsTextLogPreloader(), FieldseekerContainerrelate: buildFieldseekerContainerrelatePreloader(), @@ -139,8 +141,9 @@ var ( type thenLoaders[Q orm.Loadable] struct { ArcgisUser arcgisuserThenLoader[Q] ArcgisUserPrivilege arcgisUserPrivilegeThenLoader[Q] - CommsEmail commsEmailThenLoader[Q] + CommsEmailContact commsEmailContactThenLoader[Q] CommsEmailLog commsEmailLogThenLoader[Q] + CommsEmailTemplate commsEmailTemplateThenLoader[Q] CommsPhone commsPhoneThenLoader[Q] CommsTextLog commsTextLogThenLoader[Q] FieldseekerContainerrelate fieldseekerContainerrelateThenLoader[Q] @@ -196,8 +199,9 @@ func getThenLoaders[Q orm.Loadable]() thenLoaders[Q] { return thenLoaders[Q]{ ArcgisUser: buildArcgisUserThenLoader[Q](), ArcgisUserPrivilege: buildArcgisUserPrivilegeThenLoader[Q](), - CommsEmail: buildCommsEmailThenLoader[Q](), + CommsEmailContact: buildCommsEmailContactThenLoader[Q](), CommsEmailLog: buildCommsEmailLogThenLoader[Q](), + CommsEmailTemplate: buildCommsEmailTemplateThenLoader[Q](), CommsPhone: buildCommsPhoneThenLoader[Q](), CommsTextLog: buildCommsTextLogThenLoader[Q](), FieldseekerContainerrelate: buildFieldseekerContainerrelateThenLoader[Q](), diff --git a/db/models/bob_where.bob.go b/db/models/bob_where.bob.go index 9ce4788e..fad47793 100644 --- a/db/models/bob_where.bob.go +++ b/db/models/bob_where.bob.go @@ -19,8 +19,9 @@ var ( func Where[Q psql.Filterable]() struct { ArcgisUsers arcgisuserWhere[Q] ArcgisUserPrivileges arcgisUserPrivilegeWhere[Q] - CommsEmails commsEmailWhere[Q] + CommsEmailContacts commsEmailContactWhere[Q] CommsEmailLogs commsEmailLogWhere[Q] + CommsEmailTemplates commsEmailTemplateWhere[Q] CommsPhones commsPhoneWhere[Q] CommsTextLogs commsTextLogWhere[Q] FieldseekerContainerrelates fieldseekerContainerrelateWhere[Q] @@ -82,8 +83,9 @@ func Where[Q psql.Filterable]() struct { return struct { ArcgisUsers arcgisuserWhere[Q] ArcgisUserPrivileges arcgisUserPrivilegeWhere[Q] - CommsEmails commsEmailWhere[Q] + CommsEmailContacts commsEmailContactWhere[Q] CommsEmailLogs commsEmailLogWhere[Q] + CommsEmailTemplates commsEmailTemplateWhere[Q] CommsPhones commsPhoneWhere[Q] CommsTextLogs commsTextLogWhere[Q] FieldseekerContainerrelates fieldseekerContainerrelateWhere[Q] @@ -144,8 +146,9 @@ func Where[Q psql.Filterable]() struct { }{ ArcgisUsers: buildArcgisUserWhere[Q](ArcgisUsers.Columns), ArcgisUserPrivileges: buildArcgisUserPrivilegeWhere[Q](ArcgisUserPrivileges.Columns), - CommsEmails: buildCommsEmailWhere[Q](CommsEmails.Columns), + CommsEmailContacts: buildCommsEmailContactWhere[Q](CommsEmailContacts.Columns), CommsEmailLogs: buildCommsEmailLogWhere[Q](CommsEmailLogs.Columns), + CommsEmailTemplates: buildCommsEmailTemplateWhere[Q](CommsEmailTemplates.Columns), CommsPhones: buildCommsPhoneWhere[Q](CommsPhones.Columns), CommsTextLogs: buildCommsTextLogWhere[Q](CommsTextLogs.Columns), FieldseekerContainerrelates: buildFieldseekerContainerrelateWhere[Q](FieldseekerContainerrelates.Columns), diff --git a/db/models/comms.email.bob.go b/db/models/comms.email.bob.go deleted file mode 100644 index 3e05fefb..00000000 --- a/db/models/comms.email.bob.go +++ /dev/null @@ -1,737 +0,0 @@ -// Code generated by BobGen psql v0.42.1. DO NOT EDIT. -// This file is meant to be re-generated in place and/or deleted at any time. - -package models - -import ( - "context" - "fmt" - "io" - - "github.com/aarondl/opt/omit" - "github.com/stephenafamo/bob" - "github.com/stephenafamo/bob/dialect/psql" - "github.com/stephenafamo/bob/dialect/psql/dialect" - "github.com/stephenafamo/bob/dialect/psql/dm" - "github.com/stephenafamo/bob/dialect/psql/sm" - "github.com/stephenafamo/bob/dialect/psql/um" - "github.com/stephenafamo/bob/expr" - "github.com/stephenafamo/bob/mods" - "github.com/stephenafamo/bob/orm" - "github.com/stephenafamo/bob/types/pgtypes" -) - -// CommsEmail is an object representing the database table. -type CommsEmail struct { - Address string `db:"address,pk" ` - Confirmed bool `db:"confirmed" ` - IsSubscribed bool `db:"is_subscribed" ` - - R commsEmailR `db:"-" ` - - C commsEmailC `db:"-" ` -} - -// CommsEmailSlice is an alias for a slice of pointers to CommsEmail. -// This should almost always be used instead of []*CommsEmail. -type CommsEmailSlice []*CommsEmail - -// CommsEmails contains methods to work with the email table -var CommsEmails = psql.NewTablex[*CommsEmail, CommsEmailSlice, *CommsEmailSetter]("comms", "email", buildCommsEmailColumns("comms.email")) - -// CommsEmailsQuery is a query on the email table -type CommsEmailsQuery = *psql.ViewQuery[*CommsEmail, CommsEmailSlice] - -// commsEmailR is where relationships are stored. -type commsEmailR struct { - DestinationEmailLogs CommsEmailLogSlice // comms.email_log.email_log_destination_fkey -} - -func buildCommsEmailColumns(alias string) commsEmailColumns { - return commsEmailColumns{ - ColumnsExpr: expr.NewColumnsExpr( - "address", "confirmed", "is_subscribed", - ).WithParent("comms.email"), - tableAlias: alias, - Address: psql.Quote(alias, "address"), - Confirmed: psql.Quote(alias, "confirmed"), - IsSubscribed: psql.Quote(alias, "is_subscribed"), - } -} - -type commsEmailColumns struct { - expr.ColumnsExpr - tableAlias string - Address psql.Expression - Confirmed psql.Expression - IsSubscribed psql.Expression -} - -func (c commsEmailColumns) Alias() string { - return c.tableAlias -} - -func (commsEmailColumns) AliasedAs(alias string) commsEmailColumns { - return buildCommsEmailColumns(alias) -} - -// CommsEmailSetter is used for insert/upsert/update operations -// All values are optional, and do not have to be set -// Generated columns are not included -type CommsEmailSetter struct { - Address omit.Val[string] `db:"address,pk" ` - Confirmed omit.Val[bool] `db:"confirmed" ` - IsSubscribed omit.Val[bool] `db:"is_subscribed" ` -} - -func (s CommsEmailSetter) SetColumns() []string { - vals := make([]string, 0, 3) - if s.Address.IsValue() { - vals = append(vals, "address") - } - if s.Confirmed.IsValue() { - vals = append(vals, "confirmed") - } - if s.IsSubscribed.IsValue() { - vals = append(vals, "is_subscribed") - } - return vals -} - -func (s CommsEmailSetter) Overwrite(t *CommsEmail) { - if s.Address.IsValue() { - t.Address = s.Address.MustGet() - } - if s.Confirmed.IsValue() { - t.Confirmed = s.Confirmed.MustGet() - } - if s.IsSubscribed.IsValue() { - t.IsSubscribed = s.IsSubscribed.MustGet() - } -} - -func (s *CommsEmailSetter) Apply(q *dialect.InsertQuery) { - q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { - return CommsEmails.BeforeInsertHooks.RunHooks(ctx, exec, s) - }) - - q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 3) - if s.Address.IsValue() { - vals[0] = psql.Arg(s.Address.MustGet()) - } else { - vals[0] = psql.Raw("DEFAULT") - } - - if s.Confirmed.IsValue() { - vals[1] = psql.Arg(s.Confirmed.MustGet()) - } else { - vals[1] = psql.Raw("DEFAULT") - } - - if s.IsSubscribed.IsValue() { - vals[2] = psql.Arg(s.IsSubscribed.MustGet()) - } else { - vals[2] = psql.Raw("DEFAULT") - } - - return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") - })) -} - -func (s CommsEmailSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { - return um.Set(s.Expressions()...) -} - -func (s CommsEmailSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 3) - - if s.Address.IsValue() { - exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ - psql.Quote(append(prefix, "address")...), - psql.Arg(s.Address), - }}) - } - - if s.Confirmed.IsValue() { - exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ - psql.Quote(append(prefix, "confirmed")...), - psql.Arg(s.Confirmed), - }}) - } - - if s.IsSubscribed.IsValue() { - exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ - psql.Quote(append(prefix, "is_subscribed")...), - psql.Arg(s.IsSubscribed), - }}) - } - - return exprs -} - -// FindCommsEmail retrieves a single record by primary key -// If cols is empty Find will return all columns. -func FindCommsEmail(ctx context.Context, exec bob.Executor, AddressPK string, cols ...string) (*CommsEmail, error) { - if len(cols) == 0 { - return CommsEmails.Query( - sm.Where(CommsEmails.Columns.Address.EQ(psql.Arg(AddressPK))), - ).One(ctx, exec) - } - - return CommsEmails.Query( - sm.Where(CommsEmails.Columns.Address.EQ(psql.Arg(AddressPK))), - sm.Columns(CommsEmails.Columns.Only(cols...)), - ).One(ctx, exec) -} - -// CommsEmailExists checks the presence of a single record by primary key -func CommsEmailExists(ctx context.Context, exec bob.Executor, AddressPK string) (bool, error) { - return CommsEmails.Query( - sm.Where(CommsEmails.Columns.Address.EQ(psql.Arg(AddressPK))), - ).Exists(ctx, exec) -} - -// AfterQueryHook is called after CommsEmail is retrieved from the database -func (o *CommsEmail) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { - var err error - - switch queryType { - case bob.QueryTypeSelect: - ctx, err = CommsEmails.AfterSelectHooks.RunHooks(ctx, exec, CommsEmailSlice{o}) - case bob.QueryTypeInsert: - ctx, err = CommsEmails.AfterInsertHooks.RunHooks(ctx, exec, CommsEmailSlice{o}) - case bob.QueryTypeUpdate: - ctx, err = CommsEmails.AfterUpdateHooks.RunHooks(ctx, exec, CommsEmailSlice{o}) - case bob.QueryTypeDelete: - ctx, err = CommsEmails.AfterDeleteHooks.RunHooks(ctx, exec, CommsEmailSlice{o}) - } - - return err -} - -// primaryKeyVals returns the primary key values of the CommsEmail -func (o *CommsEmail) primaryKeyVals() bob.Expression { - return psql.Arg(o.Address) -} - -func (o *CommsEmail) pkEQ() dialect.Expression { - return psql.Quote("comms.email", "address").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { - return o.primaryKeyVals().WriteSQL(ctx, w, d, start) - })) -} - -// Update uses an executor to update the CommsEmail -func (o *CommsEmail) Update(ctx context.Context, exec bob.Executor, s *CommsEmailSetter) error { - v, err := CommsEmails.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec) - if err != nil { - return err - } - - o.R = v.R - *o = *v - - return nil -} - -// Delete deletes a single CommsEmail record with an executor -func (o *CommsEmail) Delete(ctx context.Context, exec bob.Executor) error { - _, err := CommsEmails.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec) - return err -} - -// Reload refreshes the CommsEmail using the executor -func (o *CommsEmail) Reload(ctx context.Context, exec bob.Executor) error { - o2, err := CommsEmails.Query( - sm.Where(CommsEmails.Columns.Address.EQ(psql.Arg(o.Address))), - ).One(ctx, exec) - if err != nil { - return err - } - o2.R = o.R - *o = *o2 - - return nil -} - -// AfterQueryHook is called after CommsEmailSlice is retrieved from the database -func (o CommsEmailSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { - var err error - - switch queryType { - case bob.QueryTypeSelect: - ctx, err = CommsEmails.AfterSelectHooks.RunHooks(ctx, exec, o) - case bob.QueryTypeInsert: - ctx, err = CommsEmails.AfterInsertHooks.RunHooks(ctx, exec, o) - case bob.QueryTypeUpdate: - ctx, err = CommsEmails.AfterUpdateHooks.RunHooks(ctx, exec, o) - case bob.QueryTypeDelete: - ctx, err = CommsEmails.AfterDeleteHooks.RunHooks(ctx, exec, o) - } - - return err -} - -func (o CommsEmailSlice) pkIN() dialect.Expression { - if len(o) == 0 { - return psql.Raw("NULL") - } - - return psql.Quote("comms.email", "address").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { - pkPairs := make([]bob.Expression, len(o)) - for i, row := range o { - pkPairs[i] = row.primaryKeyVals() - } - return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "") - })) -} - -// copyMatchingRows finds models in the given slice that have the same primary key -// then it first copies the existing relationships from the old model to the new model -// and then replaces the old model in the slice with the new model -func (o CommsEmailSlice) copyMatchingRows(from ...*CommsEmail) { - for i, old := range o { - for _, new := range from { - if new.Address != old.Address { - continue - } - new.R = old.R - o[i] = new - break - } - } -} - -// UpdateMod modifies an update query with "WHERE primary_key IN (o...)" -func (o CommsEmailSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] { - return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) { - q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { - return CommsEmails.BeforeUpdateHooks.RunHooks(ctx, exec, o) - }) - - q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { - var err error - switch retrieved := retrieved.(type) { - case *CommsEmail: - o.copyMatchingRows(retrieved) - case []*CommsEmail: - o.copyMatchingRows(retrieved...) - case CommsEmailSlice: - o.copyMatchingRows(retrieved...) - default: - // If the retrieved value is not a CommsEmail or a slice of CommsEmail - // then run the AfterUpdateHooks on the slice - _, err = CommsEmails.AfterUpdateHooks.RunHooks(ctx, exec, o) - } - - return err - })) - - q.AppendWhere(o.pkIN()) - }) -} - -// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)" -func (o CommsEmailSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] { - return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) { - q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { - return CommsEmails.BeforeDeleteHooks.RunHooks(ctx, exec, o) - }) - - q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { - var err error - switch retrieved := retrieved.(type) { - case *CommsEmail: - o.copyMatchingRows(retrieved) - case []*CommsEmail: - o.copyMatchingRows(retrieved...) - case CommsEmailSlice: - o.copyMatchingRows(retrieved...) - default: - // If the retrieved value is not a CommsEmail or a slice of CommsEmail - // then run the AfterDeleteHooks on the slice - _, err = CommsEmails.AfterDeleteHooks.RunHooks(ctx, exec, o) - } - - return err - })) - - q.AppendWhere(o.pkIN()) - }) -} - -func (o CommsEmailSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals CommsEmailSetter) error { - if len(o) == 0 { - return nil - } - - _, err := CommsEmails.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec) - return err -} - -func (o CommsEmailSlice) DeleteAll(ctx context.Context, exec bob.Executor) error { - if len(o) == 0 { - return nil - } - - _, err := CommsEmails.Delete(o.DeleteMod()).Exec(ctx, exec) - return err -} - -func (o CommsEmailSlice) ReloadAll(ctx context.Context, exec bob.Executor) error { - if len(o) == 0 { - return nil - } - - o2, err := CommsEmails.Query(sm.Where(o.pkIN())).All(ctx, exec) - if err != nil { - return err - } - - o.copyMatchingRows(o2...) - - return nil -} - -// DestinationEmailLogs starts a query for related objects on comms.email_log -func (o *CommsEmail) DestinationEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { - return CommsEmailLogs.Query(append(mods, - sm.Where(CommsEmailLogs.Columns.Destination.EQ(psql.Arg(o.Address))), - )...) -} - -func (os CommsEmailSlice) DestinationEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { - pkAddress := make(pgtypes.Array[string], 0, len(os)) - for _, o := range os { - if o == nil { - continue - } - pkAddress = append(pkAddress, o.Address) - } - PKArgExpr := psql.Select(sm.Columns( - psql.F("unnest", psql.Cast(psql.Arg(pkAddress), "text[]")), - )) - - return CommsEmailLogs.Query(append(mods, - sm.Where(psql.Group(CommsEmailLogs.Columns.Destination).OP("IN", PKArgExpr)), - )...) -} - -func insertCommsEmailDestinationEmailLogs0(ctx context.Context, exec bob.Executor, commsEmailLogs1 []*CommsEmailLogSetter, commsEmail0 *CommsEmail) (CommsEmailLogSlice, error) { - for i := range commsEmailLogs1 { - commsEmailLogs1[i].Destination = omit.From(commsEmail0.Address) - } - - ret, err := CommsEmailLogs.Insert(bob.ToMods(commsEmailLogs1...)).All(ctx, exec) - if err != nil { - return ret, fmt.Errorf("insertCommsEmailDestinationEmailLogs0: %w", err) - } - - return ret, nil -} - -func attachCommsEmailDestinationEmailLogs0(ctx context.Context, exec bob.Executor, count int, commsEmailLogs1 CommsEmailLogSlice, commsEmail0 *CommsEmail) (CommsEmailLogSlice, error) { - setter := &CommsEmailLogSetter{ - Destination: omit.From(commsEmail0.Address), - } - - err := commsEmailLogs1.UpdateAll(ctx, exec, *setter) - if err != nil { - return nil, fmt.Errorf("attachCommsEmailDestinationEmailLogs0: %w", err) - } - - return commsEmailLogs1, nil -} - -func (commsEmail0 *CommsEmail) InsertDestinationEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLogSetter) error { - if len(related) == 0 { - return nil - } - - var err error - - commsEmailLogs1, err := insertCommsEmailDestinationEmailLogs0(ctx, exec, related, commsEmail0) - if err != nil { - return err - } - - commsEmail0.R.DestinationEmailLogs = append(commsEmail0.R.DestinationEmailLogs, commsEmailLogs1...) - - for _, rel := range commsEmailLogs1 { - rel.R.DestinationEmail = commsEmail0 - } - return nil -} - -func (commsEmail0 *CommsEmail) AttachDestinationEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLog) error { - if len(related) == 0 { - return nil - } - - var err error - commsEmailLogs1 := CommsEmailLogSlice(related) - - _, err = attachCommsEmailDestinationEmailLogs0(ctx, exec, len(related), commsEmailLogs1, commsEmail0) - if err != nil { - return err - } - - commsEmail0.R.DestinationEmailLogs = append(commsEmail0.R.DestinationEmailLogs, commsEmailLogs1...) - - for _, rel := range related { - rel.R.DestinationEmail = commsEmail0 - } - - return nil -} - -type commsEmailWhere[Q psql.Filterable] struct { - Address psql.WhereMod[Q, string] - Confirmed psql.WhereMod[Q, bool] - IsSubscribed psql.WhereMod[Q, bool] -} - -func (commsEmailWhere[Q]) AliasedAs(alias string) commsEmailWhere[Q] { - return buildCommsEmailWhere[Q](buildCommsEmailColumns(alias)) -} - -func buildCommsEmailWhere[Q psql.Filterable](cols commsEmailColumns) commsEmailWhere[Q] { - return commsEmailWhere[Q]{ - Address: psql.Where[Q, string](cols.Address), - Confirmed: psql.Where[Q, bool](cols.Confirmed), - IsSubscribed: psql.Where[Q, bool](cols.IsSubscribed), - } -} - -func (o *CommsEmail) Preload(name string, retrieved any) error { - if o == nil { - return nil - } - - switch name { - case "DestinationEmailLogs": - rels, ok := retrieved.(CommsEmailLogSlice) - if !ok { - return fmt.Errorf("commsEmail cannot load %T as %q", retrieved, name) - } - - o.R.DestinationEmailLogs = rels - - for _, rel := range rels { - if rel != nil { - rel.R.DestinationEmail = o - } - } - return nil - default: - return fmt.Errorf("commsEmail has no relationship %q", name) - } -} - -type commsEmailPreloader struct{} - -func buildCommsEmailPreloader() commsEmailPreloader { - return commsEmailPreloader{} -} - -type commsEmailThenLoader[Q orm.Loadable] struct { - DestinationEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] -} - -func buildCommsEmailThenLoader[Q orm.Loadable]() commsEmailThenLoader[Q] { - type DestinationEmailLogsLoadInterface interface { - LoadDestinationEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error - } - - return commsEmailThenLoader[Q]{ - DestinationEmailLogs: thenLoadBuilder[Q]( - "DestinationEmailLogs", - func(ctx context.Context, exec bob.Executor, retrieved DestinationEmailLogsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { - return retrieved.LoadDestinationEmailLogs(ctx, exec, mods...) - }, - ), - } -} - -// LoadDestinationEmailLogs loads the commsEmail's DestinationEmailLogs into the .R struct -func (o *CommsEmail) LoadDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if o == nil { - return nil - } - - // Reset the relationship - o.R.DestinationEmailLogs = nil - - related, err := o.DestinationEmailLogs(mods...).All(ctx, exec) - if err != nil { - return err - } - - for _, rel := range related { - rel.R.DestinationEmail = o - } - - o.R.DestinationEmailLogs = related - return nil -} - -// LoadDestinationEmailLogs loads the commsEmail's DestinationEmailLogs into the .R struct -func (os CommsEmailSlice) LoadDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if len(os) == 0 { - return nil - } - - commsEmailLogs, err := os.DestinationEmailLogs(mods...).All(ctx, exec) - if err != nil { - return err - } - - for _, o := range os { - if o == nil { - continue - } - - o.R.DestinationEmailLogs = nil - } - - for _, o := range os { - if o == nil { - continue - } - - for _, rel := range commsEmailLogs { - - if !(o.Address == rel.Destination) { - continue - } - - rel.R.DestinationEmail = o - - o.R.DestinationEmailLogs = append(o.R.DestinationEmailLogs, rel) - } - } - - return nil -} - -// commsEmailC is where relationship counts are stored. -type commsEmailC struct { - DestinationEmailLogs *int64 -} - -// PreloadCount sets a count in the C struct by name -func (o *CommsEmail) PreloadCount(name string, count int64) error { - if o == nil { - return nil - } - - switch name { - case "DestinationEmailLogs": - o.C.DestinationEmailLogs = &count - } - return nil -} - -type commsEmailCountPreloader struct { - DestinationEmailLogs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader -} - -func buildCommsEmailCountPreloader() commsEmailCountPreloader { - return commsEmailCountPreloader{ - DestinationEmailLogs: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { - return countPreloader[*CommsEmail]("DestinationEmailLogs", func(parent string) bob.Expression { - // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) - if parent == "" { - parent = CommsEmails.Alias() - } - - subqueryMods := []bob.Mod[*dialect.SelectQuery]{ - sm.Columns(psql.Raw("count(*)")), - - sm.From(CommsEmailLogs.Name()), - sm.Where(psql.Quote(CommsEmailLogs.Alias(), "destination").EQ(psql.Quote(parent, "address"))), - } - subqueryMods = append(subqueryMods, mods...) - return psql.Group(psql.Select(subqueryMods...).Expression) - }) - }, - } -} - -type commsEmailCountThenLoader[Q orm.Loadable] struct { - DestinationEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] -} - -func buildCommsEmailCountThenLoader[Q orm.Loadable]() commsEmailCountThenLoader[Q] { - type DestinationEmailLogsCountInterface interface { - LoadCountDestinationEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error - } - - return commsEmailCountThenLoader[Q]{ - DestinationEmailLogs: countThenLoadBuilder[Q]( - "DestinationEmailLogs", - func(ctx context.Context, exec bob.Executor, retrieved DestinationEmailLogsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { - return retrieved.LoadCountDestinationEmailLogs(ctx, exec, mods...) - }, - ), - } -} - -// LoadCountDestinationEmailLogs loads the count of DestinationEmailLogs into the C struct -func (o *CommsEmail) LoadCountDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if o == nil { - return nil - } - - count, err := o.DestinationEmailLogs(mods...).Count(ctx, exec) - if err != nil { - return err - } - - o.C.DestinationEmailLogs = &count - return nil -} - -// LoadCountDestinationEmailLogs loads the count of DestinationEmailLogs for a slice -func (os CommsEmailSlice) LoadCountDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if len(os) == 0 { - return nil - } - - for _, o := range os { - if err := o.LoadCountDestinationEmailLogs(ctx, exec, mods...); err != nil { - return err - } - } - - return nil -} - -type commsEmailJoins[Q dialect.Joinable] struct { - typ string - DestinationEmailLogs modAs[Q, commsEmailLogColumns] -} - -func (j commsEmailJoins[Q]) aliasedAs(alias string) commsEmailJoins[Q] { - return buildCommsEmailJoins[Q](buildCommsEmailColumns(alias), j.typ) -} - -func buildCommsEmailJoins[Q dialect.Joinable](cols commsEmailColumns, typ string) commsEmailJoins[Q] { - return commsEmailJoins[Q]{ - typ: typ, - DestinationEmailLogs: modAs[Q, commsEmailLogColumns]{ - c: CommsEmailLogs.Columns, - f: func(to commsEmailLogColumns) bob.Mod[Q] { - mods := make(mods.QueryMods[Q], 0, 1) - - { - mods = append(mods, dialect.Join[Q](typ, CommsEmailLogs.Name().As(to.Alias())).On( - to.Destination.EQ(cols.Address), - )) - } - - return mods - }, - }, - } -} diff --git a/db/models/comms.email_contact.bob.go b/db/models/comms.email_contact.bob.go new file mode 100644 index 00000000..ca468f6b --- /dev/null +++ b/db/models/comms.email_contact.bob.go @@ -0,0 +1,762 @@ +// Code generated by BobGen psql v0.42.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "fmt" + "io" + + "github.com/aarondl/opt/omit" + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + "github.com/stephenafamo/bob/dialect/psql/dialect" + "github.com/stephenafamo/bob/dialect/psql/dm" + "github.com/stephenafamo/bob/dialect/psql/sm" + "github.com/stephenafamo/bob/dialect/psql/um" + "github.com/stephenafamo/bob/expr" + "github.com/stephenafamo/bob/mods" + "github.com/stephenafamo/bob/orm" + "github.com/stephenafamo/bob/types/pgtypes" +) + +// CommsEmailContact is an object representing the database table. +type CommsEmailContact struct { + Address string `db:"address,pk" ` + Confirmed bool `db:"confirmed" ` + IsSubscribed bool `db:"is_subscribed" ` + PublicID string `db:"public_id" ` + + R commsEmailContactR `db:"-" ` + + C commsEmailContactC `db:"-" ` +} + +// CommsEmailContactSlice is an alias for a slice of pointers to CommsEmailContact. +// This should almost always be used instead of []*CommsEmailContact. +type CommsEmailContactSlice []*CommsEmailContact + +// CommsEmailContacts contains methods to work with the email_contact table +var CommsEmailContacts = psql.NewTablex[*CommsEmailContact, CommsEmailContactSlice, *CommsEmailContactSetter]("comms", "email_contact", buildCommsEmailContactColumns("comms.email_contact")) + +// CommsEmailContactsQuery is a query on the email_contact table +type CommsEmailContactsQuery = *psql.ViewQuery[*CommsEmailContact, CommsEmailContactSlice] + +// commsEmailContactR is where relationships are stored. +type commsEmailContactR struct { + DestinationEmailLogs CommsEmailLogSlice // comms.email_log.email_log_destination_fkey +} + +func buildCommsEmailContactColumns(alias string) commsEmailContactColumns { + return commsEmailContactColumns{ + ColumnsExpr: expr.NewColumnsExpr( + "address", "confirmed", "is_subscribed", "public_id", + ).WithParent("comms.email_contact"), + tableAlias: alias, + Address: psql.Quote(alias, "address"), + Confirmed: psql.Quote(alias, "confirmed"), + IsSubscribed: psql.Quote(alias, "is_subscribed"), + PublicID: psql.Quote(alias, "public_id"), + } +} + +type commsEmailContactColumns struct { + expr.ColumnsExpr + tableAlias string + Address psql.Expression + Confirmed psql.Expression + IsSubscribed psql.Expression + PublicID psql.Expression +} + +func (c commsEmailContactColumns) Alias() string { + return c.tableAlias +} + +func (commsEmailContactColumns) AliasedAs(alias string) commsEmailContactColumns { + return buildCommsEmailContactColumns(alias) +} + +// CommsEmailContactSetter is used for insert/upsert/update operations +// All values are optional, and do not have to be set +// Generated columns are not included +type CommsEmailContactSetter struct { + Address omit.Val[string] `db:"address,pk" ` + Confirmed omit.Val[bool] `db:"confirmed" ` + IsSubscribed omit.Val[bool] `db:"is_subscribed" ` + PublicID omit.Val[string] `db:"public_id" ` +} + +func (s CommsEmailContactSetter) SetColumns() []string { + vals := make([]string, 0, 4) + if s.Address.IsValue() { + vals = append(vals, "address") + } + if s.Confirmed.IsValue() { + vals = append(vals, "confirmed") + } + if s.IsSubscribed.IsValue() { + vals = append(vals, "is_subscribed") + } + if s.PublicID.IsValue() { + vals = append(vals, "public_id") + } + return vals +} + +func (s CommsEmailContactSetter) Overwrite(t *CommsEmailContact) { + if s.Address.IsValue() { + t.Address = s.Address.MustGet() + } + if s.Confirmed.IsValue() { + t.Confirmed = s.Confirmed.MustGet() + } + if s.IsSubscribed.IsValue() { + t.IsSubscribed = s.IsSubscribed.MustGet() + } + if s.PublicID.IsValue() { + t.PublicID = s.PublicID.MustGet() + } +} + +func (s *CommsEmailContactSetter) Apply(q *dialect.InsertQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return CommsEmailContacts.BeforeInsertHooks.RunHooks(ctx, exec, s) + }) + + q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + vals := make([]bob.Expression, 4) + if s.Address.IsValue() { + vals[0] = psql.Arg(s.Address.MustGet()) + } else { + vals[0] = psql.Raw("DEFAULT") + } + + if s.Confirmed.IsValue() { + vals[1] = psql.Arg(s.Confirmed.MustGet()) + } else { + vals[1] = psql.Raw("DEFAULT") + } + + if s.IsSubscribed.IsValue() { + vals[2] = psql.Arg(s.IsSubscribed.MustGet()) + } else { + vals[2] = psql.Raw("DEFAULT") + } + + if s.PublicID.IsValue() { + vals[3] = psql.Arg(s.PublicID.MustGet()) + } else { + vals[3] = psql.Raw("DEFAULT") + } + + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") + })) +} + +func (s CommsEmailContactSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return um.Set(s.Expressions()...) +} + +func (s CommsEmailContactSetter) Expressions(prefix ...string) []bob.Expression { + exprs := make([]bob.Expression, 0, 4) + + if s.Address.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "address")...), + psql.Arg(s.Address), + }}) + } + + if s.Confirmed.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "confirmed")...), + psql.Arg(s.Confirmed), + }}) + } + + if s.IsSubscribed.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "is_subscribed")...), + psql.Arg(s.IsSubscribed), + }}) + } + + if s.PublicID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "public_id")...), + psql.Arg(s.PublicID), + }}) + } + + return exprs +} + +// FindCommsEmailContact retrieves a single record by primary key +// If cols is empty Find will return all columns. +func FindCommsEmailContact(ctx context.Context, exec bob.Executor, AddressPK string, cols ...string) (*CommsEmailContact, error) { + if len(cols) == 0 { + return CommsEmailContacts.Query( + sm.Where(CommsEmailContacts.Columns.Address.EQ(psql.Arg(AddressPK))), + ).One(ctx, exec) + } + + return CommsEmailContacts.Query( + sm.Where(CommsEmailContacts.Columns.Address.EQ(psql.Arg(AddressPK))), + sm.Columns(CommsEmailContacts.Columns.Only(cols...)), + ).One(ctx, exec) +} + +// CommsEmailContactExists checks the presence of a single record by primary key +func CommsEmailContactExists(ctx context.Context, exec bob.Executor, AddressPK string) (bool, error) { + return CommsEmailContacts.Query( + sm.Where(CommsEmailContacts.Columns.Address.EQ(psql.Arg(AddressPK))), + ).Exists(ctx, exec) +} + +// AfterQueryHook is called after CommsEmailContact is retrieved from the database +func (o *CommsEmailContact) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = CommsEmailContacts.AfterSelectHooks.RunHooks(ctx, exec, CommsEmailContactSlice{o}) + case bob.QueryTypeInsert: + ctx, err = CommsEmailContacts.AfterInsertHooks.RunHooks(ctx, exec, CommsEmailContactSlice{o}) + case bob.QueryTypeUpdate: + ctx, err = CommsEmailContacts.AfterUpdateHooks.RunHooks(ctx, exec, CommsEmailContactSlice{o}) + case bob.QueryTypeDelete: + ctx, err = CommsEmailContacts.AfterDeleteHooks.RunHooks(ctx, exec, CommsEmailContactSlice{o}) + } + + return err +} + +// primaryKeyVals returns the primary key values of the CommsEmailContact +func (o *CommsEmailContact) primaryKeyVals() bob.Expression { + return psql.Arg(o.Address) +} + +func (o *CommsEmailContact) pkEQ() dialect.Expression { + return psql.Quote("comms.email_contact", "address").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return o.primaryKeyVals().WriteSQL(ctx, w, d, start) + })) +} + +// Update uses an executor to update the CommsEmailContact +func (o *CommsEmailContact) Update(ctx context.Context, exec bob.Executor, s *CommsEmailContactSetter) error { + v, err := CommsEmailContacts.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec) + if err != nil { + return err + } + + o.R = v.R + *o = *v + + return nil +} + +// Delete deletes a single CommsEmailContact record with an executor +func (o *CommsEmailContact) Delete(ctx context.Context, exec bob.Executor) error { + _, err := CommsEmailContacts.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec) + return err +} + +// Reload refreshes the CommsEmailContact using the executor +func (o *CommsEmailContact) Reload(ctx context.Context, exec bob.Executor) error { + o2, err := CommsEmailContacts.Query( + sm.Where(CommsEmailContacts.Columns.Address.EQ(psql.Arg(o.Address))), + ).One(ctx, exec) + if err != nil { + return err + } + o2.R = o.R + *o = *o2 + + return nil +} + +// AfterQueryHook is called after CommsEmailContactSlice is retrieved from the database +func (o CommsEmailContactSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = CommsEmailContacts.AfterSelectHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeInsert: + ctx, err = CommsEmailContacts.AfterInsertHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeUpdate: + ctx, err = CommsEmailContacts.AfterUpdateHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeDelete: + ctx, err = CommsEmailContacts.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err +} + +func (o CommsEmailContactSlice) pkIN() dialect.Expression { + if len(o) == 0 { + return psql.Raw("NULL") + } + + return psql.Quote("comms.email_contact", "address").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + pkPairs := make([]bob.Expression, len(o)) + for i, row := range o { + pkPairs[i] = row.primaryKeyVals() + } + return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "") + })) +} + +// copyMatchingRows finds models in the given slice that have the same primary key +// then it first copies the existing relationships from the old model to the new model +// and then replaces the old model in the slice with the new model +func (o CommsEmailContactSlice) copyMatchingRows(from ...*CommsEmailContact) { + for i, old := range o { + for _, new := range from { + if new.Address != old.Address { + continue + } + new.R = old.R + o[i] = new + break + } + } +} + +// UpdateMod modifies an update query with "WHERE primary_key IN (o...)" +func (o CommsEmailContactSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return CommsEmailContacts.BeforeUpdateHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *CommsEmailContact: + o.copyMatchingRows(retrieved) + case []*CommsEmailContact: + o.copyMatchingRows(retrieved...) + case CommsEmailContactSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a CommsEmailContact or a slice of CommsEmailContact + // then run the AfterUpdateHooks on the slice + _, err = CommsEmailContacts.AfterUpdateHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)" +func (o CommsEmailContactSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] { + return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return CommsEmailContacts.BeforeDeleteHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *CommsEmailContact: + o.copyMatchingRows(retrieved) + case []*CommsEmailContact: + o.copyMatchingRows(retrieved...) + case CommsEmailContactSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a CommsEmailContact or a slice of CommsEmailContact + // then run the AfterDeleteHooks on the slice + _, err = CommsEmailContacts.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +func (o CommsEmailContactSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals CommsEmailContactSetter) error { + if len(o) == 0 { + return nil + } + + _, err := CommsEmailContacts.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec) + return err +} + +func (o CommsEmailContactSlice) DeleteAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + _, err := CommsEmailContacts.Delete(o.DeleteMod()).Exec(ctx, exec) + return err +} + +func (o CommsEmailContactSlice) ReloadAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + o2, err := CommsEmailContacts.Query(sm.Where(o.pkIN())).All(ctx, exec) + if err != nil { + return err + } + + o.copyMatchingRows(o2...) + + return nil +} + +// DestinationEmailLogs starts a query for related objects on comms.email_log +func (o *CommsEmailContact) DestinationEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { + return CommsEmailLogs.Query(append(mods, + sm.Where(CommsEmailLogs.Columns.Destination.EQ(psql.Arg(o.Address))), + )...) +} + +func (os CommsEmailContactSlice) DestinationEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { + pkAddress := make(pgtypes.Array[string], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkAddress = append(pkAddress, o.Address) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkAddress), "text[]")), + )) + + return CommsEmailLogs.Query(append(mods, + sm.Where(psql.Group(CommsEmailLogs.Columns.Destination).OP("IN", PKArgExpr)), + )...) +} + +func insertCommsEmailContactDestinationEmailLogs0(ctx context.Context, exec bob.Executor, commsEmailLogs1 []*CommsEmailLogSetter, commsEmailContact0 *CommsEmailContact) (CommsEmailLogSlice, error) { + for i := range commsEmailLogs1 { + commsEmailLogs1[i].Destination = omit.From(commsEmailContact0.Address) + } + + ret, err := CommsEmailLogs.Insert(bob.ToMods(commsEmailLogs1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertCommsEmailContactDestinationEmailLogs0: %w", err) + } + + return ret, nil +} + +func attachCommsEmailContactDestinationEmailLogs0(ctx context.Context, exec bob.Executor, count int, commsEmailLogs1 CommsEmailLogSlice, commsEmailContact0 *CommsEmailContact) (CommsEmailLogSlice, error) { + setter := &CommsEmailLogSetter{ + Destination: omit.From(commsEmailContact0.Address), + } + + err := commsEmailLogs1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachCommsEmailContactDestinationEmailLogs0: %w", err) + } + + return commsEmailLogs1, nil +} + +func (commsEmailContact0 *CommsEmailContact) InsertDestinationEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLogSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + commsEmailLogs1, err := insertCommsEmailContactDestinationEmailLogs0(ctx, exec, related, commsEmailContact0) + if err != nil { + return err + } + + commsEmailContact0.R.DestinationEmailLogs = append(commsEmailContact0.R.DestinationEmailLogs, commsEmailLogs1...) + + for _, rel := range commsEmailLogs1 { + rel.R.DestinationEmailContact = commsEmailContact0 + } + return nil +} + +func (commsEmailContact0 *CommsEmailContact) AttachDestinationEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLog) error { + if len(related) == 0 { + return nil + } + + var err error + commsEmailLogs1 := CommsEmailLogSlice(related) + + _, err = attachCommsEmailContactDestinationEmailLogs0(ctx, exec, len(related), commsEmailLogs1, commsEmailContact0) + if err != nil { + return err + } + + commsEmailContact0.R.DestinationEmailLogs = append(commsEmailContact0.R.DestinationEmailLogs, commsEmailLogs1...) + + for _, rel := range related { + rel.R.DestinationEmailContact = commsEmailContact0 + } + + return nil +} + +type commsEmailContactWhere[Q psql.Filterable] struct { + Address psql.WhereMod[Q, string] + Confirmed psql.WhereMod[Q, bool] + IsSubscribed psql.WhereMod[Q, bool] + PublicID psql.WhereMod[Q, string] +} + +func (commsEmailContactWhere[Q]) AliasedAs(alias string) commsEmailContactWhere[Q] { + return buildCommsEmailContactWhere[Q](buildCommsEmailContactColumns(alias)) +} + +func buildCommsEmailContactWhere[Q psql.Filterable](cols commsEmailContactColumns) commsEmailContactWhere[Q] { + return commsEmailContactWhere[Q]{ + Address: psql.Where[Q, string](cols.Address), + Confirmed: psql.Where[Q, bool](cols.Confirmed), + IsSubscribed: psql.Where[Q, bool](cols.IsSubscribed), + PublicID: psql.Where[Q, string](cols.PublicID), + } +} + +func (o *CommsEmailContact) Preload(name string, retrieved any) error { + if o == nil { + return nil + } + + switch name { + case "DestinationEmailLogs": + rels, ok := retrieved.(CommsEmailLogSlice) + if !ok { + return fmt.Errorf("commsEmailContact cannot load %T as %q", retrieved, name) + } + + o.R.DestinationEmailLogs = rels + + for _, rel := range rels { + if rel != nil { + rel.R.DestinationEmailContact = o + } + } + return nil + default: + return fmt.Errorf("commsEmailContact has no relationship %q", name) + } +} + +type commsEmailContactPreloader struct{} + +func buildCommsEmailContactPreloader() commsEmailContactPreloader { + return commsEmailContactPreloader{} +} + +type commsEmailContactThenLoader[Q orm.Loadable] struct { + DestinationEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildCommsEmailContactThenLoader[Q orm.Loadable]() commsEmailContactThenLoader[Q] { + type DestinationEmailLogsLoadInterface interface { + LoadDestinationEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return commsEmailContactThenLoader[Q]{ + DestinationEmailLogs: thenLoadBuilder[Q]( + "DestinationEmailLogs", + func(ctx context.Context, exec bob.Executor, retrieved DestinationEmailLogsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadDestinationEmailLogs(ctx, exec, mods...) + }, + ), + } +} + +// LoadDestinationEmailLogs loads the commsEmailContact's DestinationEmailLogs into the .R struct +func (o *CommsEmailContact) LoadDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.DestinationEmailLogs = nil + + related, err := o.DestinationEmailLogs(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.DestinationEmailContact = o + } + + o.R.DestinationEmailLogs = related + return nil +} + +// LoadDestinationEmailLogs loads the commsEmailContact's DestinationEmailLogs into the .R struct +func (os CommsEmailContactSlice) LoadDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + commsEmailLogs, err := os.DestinationEmailLogs(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.DestinationEmailLogs = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range commsEmailLogs { + + if !(o.Address == rel.Destination) { + continue + } + + rel.R.DestinationEmailContact = o + + o.R.DestinationEmailLogs = append(o.R.DestinationEmailLogs, rel) + } + } + + return nil +} + +// commsEmailContactC is where relationship counts are stored. +type commsEmailContactC struct { + DestinationEmailLogs *int64 +} + +// PreloadCount sets a count in the C struct by name +func (o *CommsEmailContact) PreloadCount(name string, count int64) error { + if o == nil { + return nil + } + + switch name { + case "DestinationEmailLogs": + o.C.DestinationEmailLogs = &count + } + return nil +} + +type commsEmailContactCountPreloader struct { + DestinationEmailLogs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader +} + +func buildCommsEmailContactCountPreloader() commsEmailContactCountPreloader { + return commsEmailContactCountPreloader{ + DestinationEmailLogs: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { + return countPreloader[*CommsEmailContact]("DestinationEmailLogs", func(parent string) bob.Expression { + // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) + if parent == "" { + parent = CommsEmailContacts.Alias() + } + + subqueryMods := []bob.Mod[*dialect.SelectQuery]{ + sm.Columns(psql.Raw("count(*)")), + + sm.From(CommsEmailLogs.Name()), + sm.Where(psql.Quote(CommsEmailLogs.Alias(), "destination").EQ(psql.Quote(parent, "address"))), + } + subqueryMods = append(subqueryMods, mods...) + return psql.Group(psql.Select(subqueryMods...).Expression) + }) + }, + } +} + +type commsEmailContactCountThenLoader[Q orm.Loadable] struct { + DestinationEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildCommsEmailContactCountThenLoader[Q orm.Loadable]() commsEmailContactCountThenLoader[Q] { + type DestinationEmailLogsCountInterface interface { + LoadCountDestinationEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return commsEmailContactCountThenLoader[Q]{ + DestinationEmailLogs: countThenLoadBuilder[Q]( + "DestinationEmailLogs", + func(ctx context.Context, exec bob.Executor, retrieved DestinationEmailLogsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCountDestinationEmailLogs(ctx, exec, mods...) + }, + ), + } +} + +// LoadCountDestinationEmailLogs loads the count of DestinationEmailLogs into the C struct +func (o *CommsEmailContact) LoadCountDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + count, err := o.DestinationEmailLogs(mods...).Count(ctx, exec) + if err != nil { + return err + } + + o.C.DestinationEmailLogs = &count + return nil +} + +// LoadCountDestinationEmailLogs loads the count of DestinationEmailLogs for a slice +func (os CommsEmailContactSlice) LoadCountDestinationEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + for _, o := range os { + if err := o.LoadCountDestinationEmailLogs(ctx, exec, mods...); err != nil { + return err + } + } + + return nil +} + +type commsEmailContactJoins[Q dialect.Joinable] struct { + typ string + DestinationEmailLogs modAs[Q, commsEmailLogColumns] +} + +func (j commsEmailContactJoins[Q]) aliasedAs(alias string) commsEmailContactJoins[Q] { + return buildCommsEmailContactJoins[Q](buildCommsEmailContactColumns(alias), j.typ) +} + +func buildCommsEmailContactJoins[Q dialect.Joinable](cols commsEmailContactColumns, typ string) commsEmailContactJoins[Q] { + return commsEmailContactJoins[Q]{ + typ: typ, + DestinationEmailLogs: modAs[Q, commsEmailLogColumns]{ + c: CommsEmailLogs.Columns, + f: func(to commsEmailLogColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, CommsEmailLogs.Name().As(to.Alias())).On( + to.Destination.EQ(cols.Address), + )) + } + + return mods + }, + }, + } +} diff --git a/db/models/comms.email_log.bob.go b/db/models/comms.email_log.bob.go index fb8edb87..ef59ff78 100644 --- a/db/models/comms.email_log.bob.go +++ b/db/models/comms.email_log.bob.go @@ -10,7 +10,9 @@ import ( "time" enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/aarondl/opt/null" "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" "github.com/stephenafamo/bob" "github.com/stephenafamo/bob/dialect/psql" "github.com/stephenafamo/bob/dialect/psql/dialect" @@ -25,10 +27,17 @@ import ( // CommsEmailLog is an object representing the database table. type CommsEmailLog struct { - Created time.Time `db:"created" ` - Destination string `db:"destination,pk" ` - Source string `db:"source,pk" ` - Type enums.CommsMessagetypeemail `db:"type,pk" ` + ID int32 `db:"id,pk" ` + Created time.Time `db:"created" ` + DeliveryStatus string `db:"delivery_status" ` + Destination string `db:"destination" ` + PublicID string `db:"public_id" ` + SentAt null.Val[time.Time] `db:"sent_at" ` + Source string `db:"source" ` + Subject string `db:"subject" ` + TemplateID null.Val[int32] `db:"template_id" ` + TemplateData pgtypes.HStore `db:"template_data" ` + Type enums.CommsMessagetypeemail `db:"type" ` R commsEmailLogR `db:"-" ` } @@ -45,30 +54,44 @@ type CommsEmailLogsQuery = *psql.ViewQuery[*CommsEmailLog, CommsEmailLogSlice] // commsEmailLogR is where relationships are stored. type commsEmailLogR struct { - DestinationEmail *CommsEmail // comms.email_log.email_log_destination_fkey - SourcePhone *CommsPhone // comms.email_log.email_log_source_fkey + DestinationEmailContact *CommsEmailContact // comms.email_log.email_log_destination_fkey + TemplateEmailTemplate *CommsEmailTemplate // comms.email_log.email_log_template_id_fkey } func buildCommsEmailLogColumns(alias string) commsEmailLogColumns { return commsEmailLogColumns{ ColumnsExpr: expr.NewColumnsExpr( - "created", "destination", "source", "type", + "id", "created", "delivery_status", "destination", "public_id", "sent_at", "source", "subject", "template_id", "template_data", "type", ).WithParent("comms.email_log"), - tableAlias: alias, - Created: psql.Quote(alias, "created"), - Destination: psql.Quote(alias, "destination"), - Source: psql.Quote(alias, "source"), - Type: psql.Quote(alias, "type"), + tableAlias: alias, + ID: psql.Quote(alias, "id"), + Created: psql.Quote(alias, "created"), + DeliveryStatus: psql.Quote(alias, "delivery_status"), + Destination: psql.Quote(alias, "destination"), + PublicID: psql.Quote(alias, "public_id"), + SentAt: psql.Quote(alias, "sent_at"), + Source: psql.Quote(alias, "source"), + Subject: psql.Quote(alias, "subject"), + TemplateID: psql.Quote(alias, "template_id"), + TemplateData: psql.Quote(alias, "template_data"), + Type: psql.Quote(alias, "type"), } } type commsEmailLogColumns struct { expr.ColumnsExpr - tableAlias string - Created psql.Expression - Destination psql.Expression - Source psql.Expression - Type psql.Expression + tableAlias string + ID psql.Expression + Created psql.Expression + DeliveryStatus psql.Expression + Destination psql.Expression + PublicID psql.Expression + SentAt psql.Expression + Source psql.Expression + Subject psql.Expression + TemplateID psql.Expression + TemplateData psql.Expression + Type psql.Expression } func (c commsEmailLogColumns) Alias() string { @@ -83,23 +106,51 @@ func (commsEmailLogColumns) AliasedAs(alias string) commsEmailLogColumns { // All values are optional, and do not have to be set // Generated columns are not included type CommsEmailLogSetter struct { - Created omit.Val[time.Time] `db:"created" ` - Destination omit.Val[string] `db:"destination,pk" ` - Source omit.Val[string] `db:"source,pk" ` - Type omit.Val[enums.CommsMessagetypeemail] `db:"type,pk" ` + ID omit.Val[int32] `db:"id,pk" ` + Created omit.Val[time.Time] `db:"created" ` + DeliveryStatus omit.Val[string] `db:"delivery_status" ` + Destination omit.Val[string] `db:"destination" ` + PublicID omit.Val[string] `db:"public_id" ` + SentAt omitnull.Val[time.Time] `db:"sent_at" ` + Source omit.Val[string] `db:"source" ` + Subject omit.Val[string] `db:"subject" ` + TemplateID omitnull.Val[int32] `db:"template_id" ` + TemplateData omit.Val[pgtypes.HStore] `db:"template_data" ` + Type omit.Val[enums.CommsMessagetypeemail] `db:"type" ` } func (s CommsEmailLogSetter) SetColumns() []string { - vals := make([]string, 0, 4) + vals := make([]string, 0, 11) + if s.ID.IsValue() { + vals = append(vals, "id") + } if s.Created.IsValue() { vals = append(vals, "created") } + if s.DeliveryStatus.IsValue() { + vals = append(vals, "delivery_status") + } if s.Destination.IsValue() { vals = append(vals, "destination") } + if s.PublicID.IsValue() { + vals = append(vals, "public_id") + } + if !s.SentAt.IsUnset() { + vals = append(vals, "sent_at") + } if s.Source.IsValue() { vals = append(vals, "source") } + if s.Subject.IsValue() { + vals = append(vals, "subject") + } + if !s.TemplateID.IsUnset() { + vals = append(vals, "template_id") + } + if s.TemplateData.IsValue() { + vals = append(vals, "template_data") + } if s.Type.IsValue() { vals = append(vals, "type") } @@ -107,15 +158,36 @@ func (s CommsEmailLogSetter) SetColumns() []string { } func (s CommsEmailLogSetter) Overwrite(t *CommsEmailLog) { + if s.ID.IsValue() { + t.ID = s.ID.MustGet() + } if s.Created.IsValue() { t.Created = s.Created.MustGet() } + if s.DeliveryStatus.IsValue() { + t.DeliveryStatus = s.DeliveryStatus.MustGet() + } if s.Destination.IsValue() { t.Destination = s.Destination.MustGet() } + if s.PublicID.IsValue() { + t.PublicID = s.PublicID.MustGet() + } + if !s.SentAt.IsUnset() { + t.SentAt = s.SentAt.MustGetNull() + } if s.Source.IsValue() { t.Source = s.Source.MustGet() } + if s.Subject.IsValue() { + t.Subject = s.Subject.MustGet() + } + if !s.TemplateID.IsUnset() { + t.TemplateID = s.TemplateID.MustGetNull() + } + if s.TemplateData.IsValue() { + t.TemplateData = s.TemplateData.MustGet() + } if s.Type.IsValue() { t.Type = s.Type.MustGet() } @@ -127,31 +199,73 @@ func (s *CommsEmailLogSetter) Apply(q *dialect.InsertQuery) { }) q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { - vals := make([]bob.Expression, 4) - if s.Created.IsValue() { - vals[0] = psql.Arg(s.Created.MustGet()) + vals := make([]bob.Expression, 11) + if s.ID.IsValue() { + vals[0] = psql.Arg(s.ID.MustGet()) } else { vals[0] = psql.Raw("DEFAULT") } - if s.Destination.IsValue() { - vals[1] = psql.Arg(s.Destination.MustGet()) + if s.Created.IsValue() { + vals[1] = psql.Arg(s.Created.MustGet()) } else { vals[1] = psql.Raw("DEFAULT") } - if s.Source.IsValue() { - vals[2] = psql.Arg(s.Source.MustGet()) + if s.DeliveryStatus.IsValue() { + vals[2] = psql.Arg(s.DeliveryStatus.MustGet()) } else { vals[2] = psql.Raw("DEFAULT") } - if s.Type.IsValue() { - vals[3] = psql.Arg(s.Type.MustGet()) + if s.Destination.IsValue() { + vals[3] = psql.Arg(s.Destination.MustGet()) } else { vals[3] = psql.Raw("DEFAULT") } + if s.PublicID.IsValue() { + vals[4] = psql.Arg(s.PublicID.MustGet()) + } else { + vals[4] = psql.Raw("DEFAULT") + } + + if !s.SentAt.IsUnset() { + vals[5] = psql.Arg(s.SentAt.MustGetNull()) + } else { + vals[5] = psql.Raw("DEFAULT") + } + + if s.Source.IsValue() { + vals[6] = psql.Arg(s.Source.MustGet()) + } else { + vals[6] = psql.Raw("DEFAULT") + } + + if s.Subject.IsValue() { + vals[7] = psql.Arg(s.Subject.MustGet()) + } else { + vals[7] = psql.Raw("DEFAULT") + } + + if !s.TemplateID.IsUnset() { + vals[8] = psql.Arg(s.TemplateID.MustGetNull()) + } else { + vals[8] = psql.Raw("DEFAULT") + } + + if s.TemplateData.IsValue() { + vals[9] = psql.Arg(s.TemplateData.MustGet()) + } else { + vals[9] = psql.Raw("DEFAULT") + } + + if s.Type.IsValue() { + vals[10] = psql.Arg(s.Type.MustGet()) + } else { + vals[10] = psql.Raw("DEFAULT") + } + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") })) } @@ -161,7 +275,14 @@ func (s CommsEmailLogSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { } func (s CommsEmailLogSetter) Expressions(prefix ...string) []bob.Expression { - exprs := make([]bob.Expression, 0, 4) + exprs := make([]bob.Expression, 0, 11) + + if s.ID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "id")...), + psql.Arg(s.ID), + }}) + } if s.Created.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ @@ -170,6 +291,13 @@ func (s CommsEmailLogSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if s.DeliveryStatus.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "delivery_status")...), + psql.Arg(s.DeliveryStatus), + }}) + } + if s.Destination.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ psql.Quote(append(prefix, "destination")...), @@ -177,6 +305,20 @@ func (s CommsEmailLogSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if s.PublicID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "public_id")...), + psql.Arg(s.PublicID), + }}) + } + + if !s.SentAt.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "sent_at")...), + psql.Arg(s.SentAt), + }}) + } + if s.Source.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ psql.Quote(append(prefix, "source")...), @@ -184,6 +326,27 @@ func (s CommsEmailLogSetter) Expressions(prefix ...string) []bob.Expression { }}) } + if s.Subject.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "subject")...), + psql.Arg(s.Subject), + }}) + } + + if !s.TemplateID.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "template_id")...), + psql.Arg(s.TemplateID), + }}) + } + + if s.TemplateData.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "template_data")...), + psql.Arg(s.TemplateData), + }}) + } + if s.Type.IsValue() { exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ psql.Quote(append(prefix, "type")...), @@ -196,29 +359,23 @@ func (s CommsEmailLogSetter) Expressions(prefix ...string) []bob.Expression { // FindCommsEmailLog retrieves a single record by primary key // If cols is empty Find will return all columns. -func FindCommsEmailLog(ctx context.Context, exec bob.Executor, DestinationPK string, SourcePK string, TypePK enums.CommsMessagetypeemail, cols ...string) (*CommsEmailLog, error) { +func FindCommsEmailLog(ctx context.Context, exec bob.Executor, IDPK int32, cols ...string) (*CommsEmailLog, error) { if len(cols) == 0 { return CommsEmailLogs.Query( - sm.Where(CommsEmailLogs.Columns.Destination.EQ(psql.Arg(DestinationPK))), - sm.Where(CommsEmailLogs.Columns.Source.EQ(psql.Arg(SourcePK))), - sm.Where(CommsEmailLogs.Columns.Type.EQ(psql.Arg(TypePK))), + sm.Where(CommsEmailLogs.Columns.ID.EQ(psql.Arg(IDPK))), ).One(ctx, exec) } return CommsEmailLogs.Query( - sm.Where(CommsEmailLogs.Columns.Destination.EQ(psql.Arg(DestinationPK))), - sm.Where(CommsEmailLogs.Columns.Source.EQ(psql.Arg(SourcePK))), - sm.Where(CommsEmailLogs.Columns.Type.EQ(psql.Arg(TypePK))), + sm.Where(CommsEmailLogs.Columns.ID.EQ(psql.Arg(IDPK))), sm.Columns(CommsEmailLogs.Columns.Only(cols...)), ).One(ctx, exec) } // CommsEmailLogExists checks the presence of a single record by primary key -func CommsEmailLogExists(ctx context.Context, exec bob.Executor, DestinationPK string, SourcePK string, TypePK enums.CommsMessagetypeemail) (bool, error) { +func CommsEmailLogExists(ctx context.Context, exec bob.Executor, IDPK int32) (bool, error) { return CommsEmailLogs.Query( - sm.Where(CommsEmailLogs.Columns.Destination.EQ(psql.Arg(DestinationPK))), - sm.Where(CommsEmailLogs.Columns.Source.EQ(psql.Arg(SourcePK))), - sm.Where(CommsEmailLogs.Columns.Type.EQ(psql.Arg(TypePK))), + sm.Where(CommsEmailLogs.Columns.ID.EQ(psql.Arg(IDPK))), ).Exists(ctx, exec) } @@ -242,15 +399,11 @@ func (o *CommsEmailLog) AfterQueryHook(ctx context.Context, exec bob.Executor, q // primaryKeyVals returns the primary key values of the CommsEmailLog func (o *CommsEmailLog) primaryKeyVals() bob.Expression { - return psql.ArgGroup( - o.Destination, - o.Source, - o.Type, - ) + return psql.Arg(o.ID) } func (o *CommsEmailLog) pkEQ() dialect.Expression { - return psql.Group(psql.Quote("comms.email_log", "destination"), psql.Quote("comms.email_log", "source"), psql.Quote("comms.email_log", "type")).EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return psql.Quote("comms.email_log", "id").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { return o.primaryKeyVals().WriteSQL(ctx, w, d, start) })) } @@ -277,9 +430,7 @@ func (o *CommsEmailLog) Delete(ctx context.Context, exec bob.Executor) error { // Reload refreshes the CommsEmailLog using the executor func (o *CommsEmailLog) Reload(ctx context.Context, exec bob.Executor) error { o2, err := CommsEmailLogs.Query( - sm.Where(CommsEmailLogs.Columns.Destination.EQ(psql.Arg(o.Destination))), - sm.Where(CommsEmailLogs.Columns.Source.EQ(psql.Arg(o.Source))), - sm.Where(CommsEmailLogs.Columns.Type.EQ(psql.Arg(o.Type))), + sm.Where(CommsEmailLogs.Columns.ID.EQ(psql.Arg(o.ID))), ).One(ctx, exec) if err != nil { return err @@ -313,7 +464,7 @@ func (o CommsEmailLogSlice) pkIN() dialect.Expression { return psql.Raw("NULL") } - return psql.Group(psql.Quote("comms.email_log", "destination"), psql.Quote("comms.email_log", "source"), psql.Quote("comms.email_log", "type")).In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return psql.Quote("comms.email_log", "id").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { pkPairs := make([]bob.Expression, len(o)) for i, row := range o { pkPairs[i] = row.primaryKeyVals() @@ -328,13 +479,7 @@ func (o CommsEmailLogSlice) pkIN() dialect.Expression { func (o CommsEmailLogSlice) copyMatchingRows(from ...*CommsEmailLog) { for i, old := range o { for _, new := range from { - if new.Destination != old.Destination { - continue - } - if new.Source != old.Source { - continue - } - if new.Type != old.Type { + if new.ID != old.ID { continue } new.R = old.R @@ -435,14 +580,14 @@ func (o CommsEmailLogSlice) ReloadAll(ctx context.Context, exec bob.Executor) er return nil } -// DestinationEmail starts a query for related objects on comms.email -func (o *CommsEmailLog) DestinationEmail(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailsQuery { - return CommsEmails.Query(append(mods, - sm.Where(CommsEmails.Columns.Address.EQ(psql.Arg(o.Destination))), +// DestinationEmailContact starts a query for related objects on comms.email_contact +func (o *CommsEmailLog) DestinationEmailContact(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailContactsQuery { + return CommsEmailContacts.Query(append(mods, + sm.Where(CommsEmailContacts.Columns.Address.EQ(psql.Arg(o.Destination))), )...) } -func (os CommsEmailLogSlice) DestinationEmail(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailsQuery { +func (os CommsEmailLogSlice) DestinationEmailContact(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailContactsQuery { pkDestination := make(pgtypes.Array[string], 0, len(os)) for _, o := range os { if o == nil { @@ -454,136 +599,143 @@ func (os CommsEmailLogSlice) DestinationEmail(mods ...bob.Mod[*dialect.SelectQue psql.F("unnest", psql.Cast(psql.Arg(pkDestination), "text[]")), )) - return CommsEmails.Query(append(mods, - sm.Where(psql.Group(CommsEmails.Columns.Address).OP("IN", PKArgExpr)), + return CommsEmailContacts.Query(append(mods, + sm.Where(psql.Group(CommsEmailContacts.Columns.Address).OP("IN", PKArgExpr)), )...) } -// SourcePhone starts a query for related objects on comms.phone -func (o *CommsEmailLog) SourcePhone(mods ...bob.Mod[*dialect.SelectQuery]) CommsPhonesQuery { - return CommsPhones.Query(append(mods, - sm.Where(CommsPhones.Columns.E164.EQ(psql.Arg(o.Source))), +// TemplateEmailTemplate starts a query for related objects on comms.email_template +func (o *CommsEmailLog) TemplateEmailTemplate(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailTemplatesQuery { + return CommsEmailTemplates.Query(append(mods, + sm.Where(CommsEmailTemplates.Columns.ID.EQ(psql.Arg(o.TemplateID))), )...) } -func (os CommsEmailLogSlice) SourcePhone(mods ...bob.Mod[*dialect.SelectQuery]) CommsPhonesQuery { - pkSource := make(pgtypes.Array[string], 0, len(os)) +func (os CommsEmailLogSlice) TemplateEmailTemplate(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailTemplatesQuery { + pkTemplateID := make(pgtypes.Array[null.Val[int32]], 0, len(os)) for _, o := range os { if o == nil { continue } - pkSource = append(pkSource, o.Source) + pkTemplateID = append(pkTemplateID, o.TemplateID) } PKArgExpr := psql.Select(sm.Columns( - psql.F("unnest", psql.Cast(psql.Arg(pkSource), "text[]")), + psql.F("unnest", psql.Cast(psql.Arg(pkTemplateID), "integer[]")), )) - return CommsPhones.Query(append(mods, - sm.Where(psql.Group(CommsPhones.Columns.E164).OP("IN", PKArgExpr)), + return CommsEmailTemplates.Query(append(mods, + sm.Where(psql.Group(CommsEmailTemplates.Columns.ID).OP("IN", PKArgExpr)), )...) } -func attachCommsEmailLogDestinationEmail0(ctx context.Context, exec bob.Executor, count int, commsEmailLog0 *CommsEmailLog, commsEmail1 *CommsEmail) (*CommsEmailLog, error) { +func attachCommsEmailLogDestinationEmailContact0(ctx context.Context, exec bob.Executor, count int, commsEmailLog0 *CommsEmailLog, commsEmailContact1 *CommsEmailContact) (*CommsEmailLog, error) { setter := &CommsEmailLogSetter{ - Destination: omit.From(commsEmail1.Address), + Destination: omit.From(commsEmailContact1.Address), } err := commsEmailLog0.Update(ctx, exec, setter) if err != nil { - return nil, fmt.Errorf("attachCommsEmailLogDestinationEmail0: %w", err) + return nil, fmt.Errorf("attachCommsEmailLogDestinationEmailContact0: %w", err) } return commsEmailLog0, nil } -func (commsEmailLog0 *CommsEmailLog) InsertDestinationEmail(ctx context.Context, exec bob.Executor, related *CommsEmailSetter) error { +func (commsEmailLog0 *CommsEmailLog) InsertDestinationEmailContact(ctx context.Context, exec bob.Executor, related *CommsEmailContactSetter) error { var err error - commsEmail1, err := CommsEmails.Insert(related).One(ctx, exec) + commsEmailContact1, err := CommsEmailContacts.Insert(related).One(ctx, exec) if err != nil { return fmt.Errorf("inserting related objects: %w", err) } - _, err = attachCommsEmailLogDestinationEmail0(ctx, exec, 1, commsEmailLog0, commsEmail1) + _, err = attachCommsEmailLogDestinationEmailContact0(ctx, exec, 1, commsEmailLog0, commsEmailContact1) if err != nil { return err } - commsEmailLog0.R.DestinationEmail = commsEmail1 + commsEmailLog0.R.DestinationEmailContact = commsEmailContact1 - commsEmail1.R.DestinationEmailLogs = append(commsEmail1.R.DestinationEmailLogs, commsEmailLog0) + commsEmailContact1.R.DestinationEmailLogs = append(commsEmailContact1.R.DestinationEmailLogs, commsEmailLog0) return nil } -func (commsEmailLog0 *CommsEmailLog) AttachDestinationEmail(ctx context.Context, exec bob.Executor, commsEmail1 *CommsEmail) error { +func (commsEmailLog0 *CommsEmailLog) AttachDestinationEmailContact(ctx context.Context, exec bob.Executor, commsEmailContact1 *CommsEmailContact) error { var err error - _, err = attachCommsEmailLogDestinationEmail0(ctx, exec, 1, commsEmailLog0, commsEmail1) + _, err = attachCommsEmailLogDestinationEmailContact0(ctx, exec, 1, commsEmailLog0, commsEmailContact1) if err != nil { return err } - commsEmailLog0.R.DestinationEmail = commsEmail1 + commsEmailLog0.R.DestinationEmailContact = commsEmailContact1 - commsEmail1.R.DestinationEmailLogs = append(commsEmail1.R.DestinationEmailLogs, commsEmailLog0) + commsEmailContact1.R.DestinationEmailLogs = append(commsEmailContact1.R.DestinationEmailLogs, commsEmailLog0) return nil } -func attachCommsEmailLogSourcePhone0(ctx context.Context, exec bob.Executor, count int, commsEmailLog0 *CommsEmailLog, commsPhone1 *CommsPhone) (*CommsEmailLog, error) { +func attachCommsEmailLogTemplateEmailTemplate0(ctx context.Context, exec bob.Executor, count int, commsEmailLog0 *CommsEmailLog, commsEmailTemplate1 *CommsEmailTemplate) (*CommsEmailLog, error) { setter := &CommsEmailLogSetter{ - Source: omit.From(commsPhone1.E164), + TemplateID: omitnull.From(commsEmailTemplate1.ID), } err := commsEmailLog0.Update(ctx, exec, setter) if err != nil { - return nil, fmt.Errorf("attachCommsEmailLogSourcePhone0: %w", err) + return nil, fmt.Errorf("attachCommsEmailLogTemplateEmailTemplate0: %w", err) } return commsEmailLog0, nil } -func (commsEmailLog0 *CommsEmailLog) InsertSourcePhone(ctx context.Context, exec bob.Executor, related *CommsPhoneSetter) error { +func (commsEmailLog0 *CommsEmailLog) InsertTemplateEmailTemplate(ctx context.Context, exec bob.Executor, related *CommsEmailTemplateSetter) error { var err error - commsPhone1, err := CommsPhones.Insert(related).One(ctx, exec) + commsEmailTemplate1, err := CommsEmailTemplates.Insert(related).One(ctx, exec) if err != nil { return fmt.Errorf("inserting related objects: %w", err) } - _, err = attachCommsEmailLogSourcePhone0(ctx, exec, 1, commsEmailLog0, commsPhone1) + _, err = attachCommsEmailLogTemplateEmailTemplate0(ctx, exec, 1, commsEmailLog0, commsEmailTemplate1) if err != nil { return err } - commsEmailLog0.R.SourcePhone = commsPhone1 + commsEmailLog0.R.TemplateEmailTemplate = commsEmailTemplate1 - commsPhone1.R.SourceEmailLogs = append(commsPhone1.R.SourceEmailLogs, commsEmailLog0) + commsEmailTemplate1.R.TemplateEmailLogs = append(commsEmailTemplate1.R.TemplateEmailLogs, commsEmailLog0) return nil } -func (commsEmailLog0 *CommsEmailLog) AttachSourcePhone(ctx context.Context, exec bob.Executor, commsPhone1 *CommsPhone) error { +func (commsEmailLog0 *CommsEmailLog) AttachTemplateEmailTemplate(ctx context.Context, exec bob.Executor, commsEmailTemplate1 *CommsEmailTemplate) error { var err error - _, err = attachCommsEmailLogSourcePhone0(ctx, exec, 1, commsEmailLog0, commsPhone1) + _, err = attachCommsEmailLogTemplateEmailTemplate0(ctx, exec, 1, commsEmailLog0, commsEmailTemplate1) if err != nil { return err } - commsEmailLog0.R.SourcePhone = commsPhone1 + commsEmailLog0.R.TemplateEmailTemplate = commsEmailTemplate1 - commsPhone1.R.SourceEmailLogs = append(commsPhone1.R.SourceEmailLogs, commsEmailLog0) + commsEmailTemplate1.R.TemplateEmailLogs = append(commsEmailTemplate1.R.TemplateEmailLogs, commsEmailLog0) return nil } type commsEmailLogWhere[Q psql.Filterable] struct { - Created psql.WhereMod[Q, time.Time] - Destination psql.WhereMod[Q, string] - Source psql.WhereMod[Q, string] - Type psql.WhereMod[Q, enums.CommsMessagetypeemail] + ID psql.WhereMod[Q, int32] + Created psql.WhereMod[Q, time.Time] + DeliveryStatus psql.WhereMod[Q, string] + Destination psql.WhereMod[Q, string] + PublicID psql.WhereMod[Q, string] + SentAt psql.WhereNullMod[Q, time.Time] + Source psql.WhereMod[Q, string] + Subject psql.WhereMod[Q, string] + TemplateID psql.WhereNullMod[Q, int32] + TemplateData psql.WhereMod[Q, pgtypes.HStore] + Type psql.WhereMod[Q, enums.CommsMessagetypeemail] } func (commsEmailLogWhere[Q]) AliasedAs(alias string) commsEmailLogWhere[Q] { @@ -592,10 +744,17 @@ func (commsEmailLogWhere[Q]) AliasedAs(alias string) commsEmailLogWhere[Q] { func buildCommsEmailLogWhere[Q psql.Filterable](cols commsEmailLogColumns) commsEmailLogWhere[Q] { return commsEmailLogWhere[Q]{ - Created: psql.Where[Q, time.Time](cols.Created), - Destination: psql.Where[Q, string](cols.Destination), - Source: psql.Where[Q, string](cols.Source), - Type: psql.Where[Q, enums.CommsMessagetypeemail](cols.Type), + ID: psql.Where[Q, int32](cols.ID), + Created: psql.Where[Q, time.Time](cols.Created), + DeliveryStatus: psql.Where[Q, string](cols.DeliveryStatus), + Destination: psql.Where[Q, string](cols.Destination), + PublicID: psql.Where[Q, string](cols.PublicID), + SentAt: psql.WhereNull[Q, time.Time](cols.SentAt), + Source: psql.Where[Q, string](cols.Source), + Subject: psql.Where[Q, string](cols.Subject), + TemplateID: psql.WhereNull[Q, int32](cols.TemplateID), + TemplateData: psql.Where[Q, pgtypes.HStore](cols.TemplateData), + Type: psql.Where[Q, enums.CommsMessagetypeemail](cols.Type), } } @@ -605,28 +764,28 @@ func (o *CommsEmailLog) Preload(name string, retrieved any) error { } switch name { - case "DestinationEmail": - rel, ok := retrieved.(*CommsEmail) + case "DestinationEmailContact": + rel, ok := retrieved.(*CommsEmailContact) if !ok { return fmt.Errorf("commsEmailLog cannot load %T as %q", retrieved, name) } - o.R.DestinationEmail = rel + o.R.DestinationEmailContact = rel if rel != nil { rel.R.DestinationEmailLogs = CommsEmailLogSlice{o} } return nil - case "SourcePhone": - rel, ok := retrieved.(*CommsPhone) + case "TemplateEmailTemplate": + rel, ok := retrieved.(*CommsEmailTemplate) if !ok { return fmt.Errorf("commsEmailLog cannot load %T as %q", retrieved, name) } - o.R.SourcePhone = rel + o.R.TemplateEmailTemplate = rel if rel != nil { - rel.R.SourceEmailLogs = CommsEmailLogSlice{o} + rel.R.TemplateEmailLogs = CommsEmailLogSlice{o} } return nil default: @@ -635,97 +794,97 @@ func (o *CommsEmailLog) Preload(name string, retrieved any) error { } type commsEmailLogPreloader struct { - DestinationEmail func(...psql.PreloadOption) psql.Preloader - SourcePhone func(...psql.PreloadOption) psql.Preloader + DestinationEmailContact func(...psql.PreloadOption) psql.Preloader + TemplateEmailTemplate func(...psql.PreloadOption) psql.Preloader } func buildCommsEmailLogPreloader() commsEmailLogPreloader { return commsEmailLogPreloader{ - DestinationEmail: func(opts ...psql.PreloadOption) psql.Preloader { - return psql.Preload[*CommsEmail, CommsEmailSlice](psql.PreloadRel{ - Name: "DestinationEmail", + DestinationEmailContact: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*CommsEmailContact, CommsEmailContactSlice](psql.PreloadRel{ + Name: "DestinationEmailContact", Sides: []psql.PreloadSide{ { From: CommsEmailLogs, - To: CommsEmails, + To: CommsEmailContacts, FromColumns: []string{"destination"}, ToColumns: []string{"address"}, }, }, - }, CommsEmails.Columns.Names(), opts...) + }, CommsEmailContacts.Columns.Names(), opts...) }, - SourcePhone: func(opts ...psql.PreloadOption) psql.Preloader { - return psql.Preload[*CommsPhone, CommsPhoneSlice](psql.PreloadRel{ - Name: "SourcePhone", + TemplateEmailTemplate: func(opts ...psql.PreloadOption) psql.Preloader { + return psql.Preload[*CommsEmailTemplate, CommsEmailTemplateSlice](psql.PreloadRel{ + Name: "TemplateEmailTemplate", Sides: []psql.PreloadSide{ { From: CommsEmailLogs, - To: CommsPhones, - FromColumns: []string{"source"}, - ToColumns: []string{"e164"}, + To: CommsEmailTemplates, + FromColumns: []string{"template_id"}, + ToColumns: []string{"id"}, }, }, - }, CommsPhones.Columns.Names(), opts...) + }, CommsEmailTemplates.Columns.Names(), opts...) }, } } type commsEmailLogThenLoader[Q orm.Loadable] struct { - DestinationEmail func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] - SourcePhone func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + DestinationEmailContact func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] + TemplateEmailTemplate func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] } func buildCommsEmailLogThenLoader[Q orm.Loadable]() commsEmailLogThenLoader[Q] { - type DestinationEmailLoadInterface interface { - LoadDestinationEmail(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + type DestinationEmailContactLoadInterface interface { + LoadDestinationEmailContact(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } - type SourcePhoneLoadInterface interface { - LoadSourcePhone(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + type TemplateEmailTemplateLoadInterface interface { + LoadTemplateEmailTemplate(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } return commsEmailLogThenLoader[Q]{ - DestinationEmail: thenLoadBuilder[Q]( - "DestinationEmail", - func(ctx context.Context, exec bob.Executor, retrieved DestinationEmailLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { - return retrieved.LoadDestinationEmail(ctx, exec, mods...) + DestinationEmailContact: thenLoadBuilder[Q]( + "DestinationEmailContact", + func(ctx context.Context, exec bob.Executor, retrieved DestinationEmailContactLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadDestinationEmailContact(ctx, exec, mods...) }, ), - SourcePhone: thenLoadBuilder[Q]( - "SourcePhone", - func(ctx context.Context, exec bob.Executor, retrieved SourcePhoneLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { - return retrieved.LoadSourcePhone(ctx, exec, mods...) + TemplateEmailTemplate: thenLoadBuilder[Q]( + "TemplateEmailTemplate", + func(ctx context.Context, exec bob.Executor, retrieved TemplateEmailTemplateLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadTemplateEmailTemplate(ctx, exec, mods...) }, ), } } -// LoadDestinationEmail loads the commsEmailLog's DestinationEmail into the .R struct -func (o *CommsEmailLog) LoadDestinationEmail(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { +// LoadDestinationEmailContact loads the commsEmailLog's DestinationEmailContact into the .R struct +func (o *CommsEmailLog) LoadDestinationEmailContact(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { return nil } // Reset the relationship - o.R.DestinationEmail = nil + o.R.DestinationEmailContact = nil - related, err := o.DestinationEmail(mods...).One(ctx, exec) + related, err := o.DestinationEmailContact(mods...).One(ctx, exec) if err != nil { return err } related.R.DestinationEmailLogs = CommsEmailLogSlice{o} - o.R.DestinationEmail = related + o.R.DestinationEmailContact = related return nil } -// LoadDestinationEmail loads the commsEmailLog's DestinationEmail into the .R struct -func (os CommsEmailLogSlice) LoadDestinationEmail(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { +// LoadDestinationEmailContact loads the commsEmailLog's DestinationEmailContact into the .R struct +func (os CommsEmailLogSlice) LoadDestinationEmailContact(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if len(os) == 0 { return nil } - commsEmails, err := os.DestinationEmail(mods...).All(ctx, exec) + commsEmailContacts, err := os.DestinationEmailContact(mods...).All(ctx, exec) if err != nil { return err } @@ -735,7 +894,7 @@ func (os CommsEmailLogSlice) LoadDestinationEmail(ctx context.Context, exec bob. continue } - for _, rel := range commsEmails { + for _, rel := range commsEmailContacts { if !(o.Destination == rel.Address) { continue @@ -743,7 +902,7 @@ func (os CommsEmailLogSlice) LoadDestinationEmail(ctx context.Context, exec bob. rel.R.DestinationEmailLogs = append(rel.R.DestinationEmailLogs, o) - o.R.DestinationEmail = rel + o.R.DestinationEmailContact = rel break } } @@ -751,33 +910,33 @@ func (os CommsEmailLogSlice) LoadDestinationEmail(ctx context.Context, exec bob. return nil } -// LoadSourcePhone loads the commsEmailLog's SourcePhone into the .R struct -func (o *CommsEmailLog) LoadSourcePhone(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { +// LoadTemplateEmailTemplate loads the commsEmailLog's TemplateEmailTemplate into the .R struct +func (o *CommsEmailLog) LoadTemplateEmailTemplate(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { return nil } // Reset the relationship - o.R.SourcePhone = nil + o.R.TemplateEmailTemplate = nil - related, err := o.SourcePhone(mods...).One(ctx, exec) + related, err := o.TemplateEmailTemplate(mods...).One(ctx, exec) if err != nil { return err } - related.R.SourceEmailLogs = CommsEmailLogSlice{o} + related.R.TemplateEmailLogs = CommsEmailLogSlice{o} - o.R.SourcePhone = related + o.R.TemplateEmailTemplate = related return nil } -// LoadSourcePhone loads the commsEmailLog's SourcePhone into the .R struct -func (os CommsEmailLogSlice) LoadSourcePhone(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { +// LoadTemplateEmailTemplate loads the commsEmailLog's TemplateEmailTemplate into the .R struct +func (os CommsEmailLogSlice) LoadTemplateEmailTemplate(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if len(os) == 0 { return nil } - commsPhones, err := os.SourcePhone(mods...).All(ctx, exec) + commsEmailTemplates, err := os.TemplateEmailTemplate(mods...).All(ctx, exec) if err != nil { return err } @@ -787,15 +946,18 @@ func (os CommsEmailLogSlice) LoadSourcePhone(ctx context.Context, exec bob.Execu continue } - for _, rel := range commsPhones { - - if !(o.Source == rel.E164) { + for _, rel := range commsEmailTemplates { + if !o.TemplateID.IsValue() { continue } - rel.R.SourceEmailLogs = append(rel.R.SourceEmailLogs, o) + if !(o.TemplateID.IsValue() && o.TemplateID.MustGet() == rel.ID) { + continue + } - o.R.SourcePhone = rel + rel.R.TemplateEmailLogs = append(rel.R.TemplateEmailLogs, o) + + o.R.TemplateEmailTemplate = rel break } } @@ -804,9 +966,9 @@ func (os CommsEmailLogSlice) LoadSourcePhone(ctx context.Context, exec bob.Execu } type commsEmailLogJoins[Q dialect.Joinable] struct { - typ string - DestinationEmail modAs[Q, commsEmailColumns] - SourcePhone modAs[Q, commsPhoneColumns] + typ string + DestinationEmailContact modAs[Q, commsEmailContactColumns] + TemplateEmailTemplate modAs[Q, commsEmailTemplateColumns] } func (j commsEmailLogJoins[Q]) aliasedAs(alias string) commsEmailLogJoins[Q] { @@ -816,13 +978,13 @@ func (j commsEmailLogJoins[Q]) aliasedAs(alias string) commsEmailLogJoins[Q] { func buildCommsEmailLogJoins[Q dialect.Joinable](cols commsEmailLogColumns, typ string) commsEmailLogJoins[Q] { return commsEmailLogJoins[Q]{ typ: typ, - DestinationEmail: modAs[Q, commsEmailColumns]{ - c: CommsEmails.Columns, - f: func(to commsEmailColumns) bob.Mod[Q] { + DestinationEmailContact: modAs[Q, commsEmailContactColumns]{ + c: CommsEmailContacts.Columns, + f: func(to commsEmailContactColumns) bob.Mod[Q] { mods := make(mods.QueryMods[Q], 0, 1) { - mods = append(mods, dialect.Join[Q](typ, CommsEmails.Name().As(to.Alias())).On( + mods = append(mods, dialect.Join[Q](typ, CommsEmailContacts.Name().As(to.Alias())).On( to.Address.EQ(cols.Destination), )) } @@ -830,14 +992,14 @@ func buildCommsEmailLogJoins[Q dialect.Joinable](cols commsEmailLogColumns, typ return mods }, }, - SourcePhone: modAs[Q, commsPhoneColumns]{ - c: CommsPhones.Columns, - f: func(to commsPhoneColumns) bob.Mod[Q] { + TemplateEmailTemplate: modAs[Q, commsEmailTemplateColumns]{ + c: CommsEmailTemplates.Columns, + f: func(to commsEmailTemplateColumns) bob.Mod[Q] { mods := make(mods.QueryMods[Q], 0, 1) { - mods = append(mods, dialect.Join[Q](typ, CommsPhones.Name().As(to.Alias())).On( - to.E164.EQ(cols.Source), + mods = append(mods, dialect.Join[Q](typ, CommsEmailTemplates.Name().As(to.Alias())).On( + to.ID.EQ(cols.TemplateID), )) } diff --git a/db/models/comms.email_template.bob.go b/db/models/comms.email_template.bob.go new file mode 100644 index 00000000..ca95017d --- /dev/null +++ b/db/models/comms.email_template.bob.go @@ -0,0 +1,869 @@ +// Code generated by BobGen psql v0.42.1. DO NOT EDIT. +// This file is meant to be re-generated in place and/or deleted at any time. + +package models + +import ( + "context" + "fmt" + "io" + "time" + + enums "github.com/Gleipnir-Technology/nidus-sync/db/enums" + "github.com/aarondl/opt/null" + "github.com/aarondl/opt/omit" + "github.com/aarondl/opt/omitnull" + "github.com/stephenafamo/bob" + "github.com/stephenafamo/bob/dialect/psql" + "github.com/stephenafamo/bob/dialect/psql/dialect" + "github.com/stephenafamo/bob/dialect/psql/dm" + "github.com/stephenafamo/bob/dialect/psql/sm" + "github.com/stephenafamo/bob/dialect/psql/um" + "github.com/stephenafamo/bob/expr" + "github.com/stephenafamo/bob/mods" + "github.com/stephenafamo/bob/orm" + "github.com/stephenafamo/bob/types/pgtypes" +) + +// CommsEmailTemplate is an object representing the database table. +type CommsEmailTemplate struct { + ContentHTML string `db:"content_html" ` + ContentTXT string `db:"content_txt" ` + ContentHashHTML string `db:"content_hash_html" ` + ContentHashTXT string `db:"content_hash_txt" ` + Created time.Time `db:"created" ` + ID int32 `db:"id,pk" ` + Superceded null.Val[time.Time] `db:"superceded" ` + MessageType enums.CommsMessagetypeemail `db:"message_type" ` + + R commsEmailTemplateR `db:"-" ` + + C commsEmailTemplateC `db:"-" ` +} + +// CommsEmailTemplateSlice is an alias for a slice of pointers to CommsEmailTemplate. +// This should almost always be used instead of []*CommsEmailTemplate. +type CommsEmailTemplateSlice []*CommsEmailTemplate + +// CommsEmailTemplates contains methods to work with the email_template table +var CommsEmailTemplates = psql.NewTablex[*CommsEmailTemplate, CommsEmailTemplateSlice, *CommsEmailTemplateSetter]("comms", "email_template", buildCommsEmailTemplateColumns("comms.email_template")) + +// CommsEmailTemplatesQuery is a query on the email_template table +type CommsEmailTemplatesQuery = *psql.ViewQuery[*CommsEmailTemplate, CommsEmailTemplateSlice] + +// commsEmailTemplateR is where relationships are stored. +type commsEmailTemplateR struct { + TemplateEmailLogs CommsEmailLogSlice // comms.email_log.email_log_template_id_fkey +} + +func buildCommsEmailTemplateColumns(alias string) commsEmailTemplateColumns { + return commsEmailTemplateColumns{ + ColumnsExpr: expr.NewColumnsExpr( + "content_html", "content_txt", "content_hash_html", "content_hash_txt", "created", "id", "superceded", "message_type", + ).WithParent("comms.email_template"), + tableAlias: alias, + ContentHTML: psql.Quote(alias, "content_html"), + ContentTXT: psql.Quote(alias, "content_txt"), + ContentHashHTML: psql.Quote(alias, "content_hash_html"), + ContentHashTXT: psql.Quote(alias, "content_hash_txt"), + Created: psql.Quote(alias, "created"), + ID: psql.Quote(alias, "id"), + Superceded: psql.Quote(alias, "superceded"), + MessageType: psql.Quote(alias, "message_type"), + } +} + +type commsEmailTemplateColumns struct { + expr.ColumnsExpr + tableAlias string + ContentHTML psql.Expression + ContentTXT psql.Expression + ContentHashHTML psql.Expression + ContentHashTXT psql.Expression + Created psql.Expression + ID psql.Expression + Superceded psql.Expression + MessageType psql.Expression +} + +func (c commsEmailTemplateColumns) Alias() string { + return c.tableAlias +} + +func (commsEmailTemplateColumns) AliasedAs(alias string) commsEmailTemplateColumns { + return buildCommsEmailTemplateColumns(alias) +} + +// CommsEmailTemplateSetter is used for insert/upsert/update operations +// All values are optional, and do not have to be set +// Generated columns are not included +type CommsEmailTemplateSetter struct { + ContentHTML omit.Val[string] `db:"content_html" ` + ContentTXT omit.Val[string] `db:"content_txt" ` + ContentHashHTML omit.Val[string] `db:"content_hash_html" ` + ContentHashTXT omit.Val[string] `db:"content_hash_txt" ` + Created omit.Val[time.Time] `db:"created" ` + ID omit.Val[int32] `db:"id,pk" ` + Superceded omitnull.Val[time.Time] `db:"superceded" ` + MessageType omit.Val[enums.CommsMessagetypeemail] `db:"message_type" ` +} + +func (s CommsEmailTemplateSetter) SetColumns() []string { + vals := make([]string, 0, 8) + if s.ContentHTML.IsValue() { + vals = append(vals, "content_html") + } + if s.ContentTXT.IsValue() { + vals = append(vals, "content_txt") + } + if s.ContentHashHTML.IsValue() { + vals = append(vals, "content_hash_html") + } + if s.ContentHashTXT.IsValue() { + vals = append(vals, "content_hash_txt") + } + if s.Created.IsValue() { + vals = append(vals, "created") + } + if s.ID.IsValue() { + vals = append(vals, "id") + } + if !s.Superceded.IsUnset() { + vals = append(vals, "superceded") + } + if s.MessageType.IsValue() { + vals = append(vals, "message_type") + } + return vals +} + +func (s CommsEmailTemplateSetter) Overwrite(t *CommsEmailTemplate) { + if s.ContentHTML.IsValue() { + t.ContentHTML = s.ContentHTML.MustGet() + } + if s.ContentTXT.IsValue() { + t.ContentTXT = s.ContentTXT.MustGet() + } + if s.ContentHashHTML.IsValue() { + t.ContentHashHTML = s.ContentHashHTML.MustGet() + } + if s.ContentHashTXT.IsValue() { + t.ContentHashTXT = s.ContentHashTXT.MustGet() + } + if s.Created.IsValue() { + t.Created = s.Created.MustGet() + } + if s.ID.IsValue() { + t.ID = s.ID.MustGet() + } + if !s.Superceded.IsUnset() { + t.Superceded = s.Superceded.MustGetNull() + } + if s.MessageType.IsValue() { + t.MessageType = s.MessageType.MustGet() + } +} + +func (s *CommsEmailTemplateSetter) Apply(q *dialect.InsertQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return CommsEmailTemplates.BeforeInsertHooks.RunHooks(ctx, exec, s) + }) + + q.AppendValues(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + vals := make([]bob.Expression, 8) + if s.ContentHTML.IsValue() { + vals[0] = psql.Arg(s.ContentHTML.MustGet()) + } else { + vals[0] = psql.Raw("DEFAULT") + } + + if s.ContentTXT.IsValue() { + vals[1] = psql.Arg(s.ContentTXT.MustGet()) + } else { + vals[1] = psql.Raw("DEFAULT") + } + + if s.ContentHashHTML.IsValue() { + vals[2] = psql.Arg(s.ContentHashHTML.MustGet()) + } else { + vals[2] = psql.Raw("DEFAULT") + } + + if s.ContentHashTXT.IsValue() { + vals[3] = psql.Arg(s.ContentHashTXT.MustGet()) + } else { + vals[3] = psql.Raw("DEFAULT") + } + + if s.Created.IsValue() { + vals[4] = psql.Arg(s.Created.MustGet()) + } else { + vals[4] = psql.Raw("DEFAULT") + } + + if s.ID.IsValue() { + vals[5] = psql.Arg(s.ID.MustGet()) + } else { + vals[5] = psql.Raw("DEFAULT") + } + + if !s.Superceded.IsUnset() { + vals[6] = psql.Arg(s.Superceded.MustGetNull()) + } else { + vals[6] = psql.Raw("DEFAULT") + } + + if s.MessageType.IsValue() { + vals[7] = psql.Arg(s.MessageType.MustGet()) + } else { + vals[7] = psql.Raw("DEFAULT") + } + + return bob.ExpressSlice(ctx, w, d, start, vals, "", ", ", "") + })) +} + +func (s CommsEmailTemplateSetter) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return um.Set(s.Expressions()...) +} + +func (s CommsEmailTemplateSetter) Expressions(prefix ...string) []bob.Expression { + exprs := make([]bob.Expression, 0, 8) + + if s.ContentHTML.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "content_html")...), + psql.Arg(s.ContentHTML), + }}) + } + + if s.ContentTXT.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "content_txt")...), + psql.Arg(s.ContentTXT), + }}) + } + + if s.ContentHashHTML.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "content_hash_html")...), + psql.Arg(s.ContentHashHTML), + }}) + } + + if s.ContentHashTXT.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "content_hash_txt")...), + psql.Arg(s.ContentHashTXT), + }}) + } + + if s.Created.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "created")...), + psql.Arg(s.Created), + }}) + } + + if s.ID.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "id")...), + psql.Arg(s.ID), + }}) + } + + if !s.Superceded.IsUnset() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "superceded")...), + psql.Arg(s.Superceded), + }}) + } + + if s.MessageType.IsValue() { + exprs = append(exprs, expr.Join{Sep: " = ", Exprs: []bob.Expression{ + psql.Quote(append(prefix, "message_type")...), + psql.Arg(s.MessageType), + }}) + } + + return exprs +} + +// FindCommsEmailTemplate retrieves a single record by primary key +// If cols is empty Find will return all columns. +func FindCommsEmailTemplate(ctx context.Context, exec bob.Executor, IDPK int32, cols ...string) (*CommsEmailTemplate, error) { + if len(cols) == 0 { + return CommsEmailTemplates.Query( + sm.Where(CommsEmailTemplates.Columns.ID.EQ(psql.Arg(IDPK))), + ).One(ctx, exec) + } + + return CommsEmailTemplates.Query( + sm.Where(CommsEmailTemplates.Columns.ID.EQ(psql.Arg(IDPK))), + sm.Columns(CommsEmailTemplates.Columns.Only(cols...)), + ).One(ctx, exec) +} + +// CommsEmailTemplateExists checks the presence of a single record by primary key +func CommsEmailTemplateExists(ctx context.Context, exec bob.Executor, IDPK int32) (bool, error) { + return CommsEmailTemplates.Query( + sm.Where(CommsEmailTemplates.Columns.ID.EQ(psql.Arg(IDPK))), + ).Exists(ctx, exec) +} + +// AfterQueryHook is called after CommsEmailTemplate is retrieved from the database +func (o *CommsEmailTemplate) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = CommsEmailTemplates.AfterSelectHooks.RunHooks(ctx, exec, CommsEmailTemplateSlice{o}) + case bob.QueryTypeInsert: + ctx, err = CommsEmailTemplates.AfterInsertHooks.RunHooks(ctx, exec, CommsEmailTemplateSlice{o}) + case bob.QueryTypeUpdate: + ctx, err = CommsEmailTemplates.AfterUpdateHooks.RunHooks(ctx, exec, CommsEmailTemplateSlice{o}) + case bob.QueryTypeDelete: + ctx, err = CommsEmailTemplates.AfterDeleteHooks.RunHooks(ctx, exec, CommsEmailTemplateSlice{o}) + } + + return err +} + +// primaryKeyVals returns the primary key values of the CommsEmailTemplate +func (o *CommsEmailTemplate) primaryKeyVals() bob.Expression { + return psql.Arg(o.ID) +} + +func (o *CommsEmailTemplate) pkEQ() dialect.Expression { + return psql.Quote("comms.email_template", "id").EQ(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + return o.primaryKeyVals().WriteSQL(ctx, w, d, start) + })) +} + +// Update uses an executor to update the CommsEmailTemplate +func (o *CommsEmailTemplate) Update(ctx context.Context, exec bob.Executor, s *CommsEmailTemplateSetter) error { + v, err := CommsEmailTemplates.Update(s.UpdateMod(), um.Where(o.pkEQ())).One(ctx, exec) + if err != nil { + return err + } + + o.R = v.R + *o = *v + + return nil +} + +// Delete deletes a single CommsEmailTemplate record with an executor +func (o *CommsEmailTemplate) Delete(ctx context.Context, exec bob.Executor) error { + _, err := CommsEmailTemplates.Delete(dm.Where(o.pkEQ())).Exec(ctx, exec) + return err +} + +// Reload refreshes the CommsEmailTemplate using the executor +func (o *CommsEmailTemplate) Reload(ctx context.Context, exec bob.Executor) error { + o2, err := CommsEmailTemplates.Query( + sm.Where(CommsEmailTemplates.Columns.ID.EQ(psql.Arg(o.ID))), + ).One(ctx, exec) + if err != nil { + return err + } + o2.R = o.R + *o = *o2 + + return nil +} + +// AfterQueryHook is called after CommsEmailTemplateSlice is retrieved from the database +func (o CommsEmailTemplateSlice) AfterQueryHook(ctx context.Context, exec bob.Executor, queryType bob.QueryType) error { + var err error + + switch queryType { + case bob.QueryTypeSelect: + ctx, err = CommsEmailTemplates.AfterSelectHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeInsert: + ctx, err = CommsEmailTemplates.AfterInsertHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeUpdate: + ctx, err = CommsEmailTemplates.AfterUpdateHooks.RunHooks(ctx, exec, o) + case bob.QueryTypeDelete: + ctx, err = CommsEmailTemplates.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err +} + +func (o CommsEmailTemplateSlice) pkIN() dialect.Expression { + if len(o) == 0 { + return psql.Raw("NULL") + } + + return psql.Quote("comms.email_template", "id").In(bob.ExpressionFunc(func(ctx context.Context, w io.StringWriter, d bob.Dialect, start int) ([]any, error) { + pkPairs := make([]bob.Expression, len(o)) + for i, row := range o { + pkPairs[i] = row.primaryKeyVals() + } + return bob.ExpressSlice(ctx, w, d, start, pkPairs, "", ", ", "") + })) +} + +// copyMatchingRows finds models in the given slice that have the same primary key +// then it first copies the existing relationships from the old model to the new model +// and then replaces the old model in the slice with the new model +func (o CommsEmailTemplateSlice) copyMatchingRows(from ...*CommsEmailTemplate) { + for i, old := range o { + for _, new := range from { + if new.ID != old.ID { + continue + } + new.R = old.R + o[i] = new + break + } + } +} + +// UpdateMod modifies an update query with "WHERE primary_key IN (o...)" +func (o CommsEmailTemplateSlice) UpdateMod() bob.Mod[*dialect.UpdateQuery] { + return bob.ModFunc[*dialect.UpdateQuery](func(q *dialect.UpdateQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return CommsEmailTemplates.BeforeUpdateHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *CommsEmailTemplate: + o.copyMatchingRows(retrieved) + case []*CommsEmailTemplate: + o.copyMatchingRows(retrieved...) + case CommsEmailTemplateSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a CommsEmailTemplate or a slice of CommsEmailTemplate + // then run the AfterUpdateHooks on the slice + _, err = CommsEmailTemplates.AfterUpdateHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +// DeleteMod modifies an delete query with "WHERE primary_key IN (o...)" +func (o CommsEmailTemplateSlice) DeleteMod() bob.Mod[*dialect.DeleteQuery] { + return bob.ModFunc[*dialect.DeleteQuery](func(q *dialect.DeleteQuery) { + q.AppendHooks(func(ctx context.Context, exec bob.Executor) (context.Context, error) { + return CommsEmailTemplates.BeforeDeleteHooks.RunHooks(ctx, exec, o) + }) + + q.AppendLoader(bob.LoaderFunc(func(ctx context.Context, exec bob.Executor, retrieved any) error { + var err error + switch retrieved := retrieved.(type) { + case *CommsEmailTemplate: + o.copyMatchingRows(retrieved) + case []*CommsEmailTemplate: + o.copyMatchingRows(retrieved...) + case CommsEmailTemplateSlice: + o.copyMatchingRows(retrieved...) + default: + // If the retrieved value is not a CommsEmailTemplate or a slice of CommsEmailTemplate + // then run the AfterDeleteHooks on the slice + _, err = CommsEmailTemplates.AfterDeleteHooks.RunHooks(ctx, exec, o) + } + + return err + })) + + q.AppendWhere(o.pkIN()) + }) +} + +func (o CommsEmailTemplateSlice) UpdateAll(ctx context.Context, exec bob.Executor, vals CommsEmailTemplateSetter) error { + if len(o) == 0 { + return nil + } + + _, err := CommsEmailTemplates.Update(vals.UpdateMod(), o.UpdateMod()).All(ctx, exec) + return err +} + +func (o CommsEmailTemplateSlice) DeleteAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + _, err := CommsEmailTemplates.Delete(o.DeleteMod()).Exec(ctx, exec) + return err +} + +func (o CommsEmailTemplateSlice) ReloadAll(ctx context.Context, exec bob.Executor) error { + if len(o) == 0 { + return nil + } + + o2, err := CommsEmailTemplates.Query(sm.Where(o.pkIN())).All(ctx, exec) + if err != nil { + return err + } + + o.copyMatchingRows(o2...) + + return nil +} + +// TemplateEmailLogs starts a query for related objects on comms.email_log +func (o *CommsEmailTemplate) TemplateEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { + return CommsEmailLogs.Query(append(mods, + sm.Where(CommsEmailLogs.Columns.TemplateID.EQ(psql.Arg(o.ID))), + )...) +} + +func (os CommsEmailTemplateSlice) TemplateEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { + pkID := make(pgtypes.Array[int32], 0, len(os)) + for _, o := range os { + if o == nil { + continue + } + pkID = append(pkID, o.ID) + } + PKArgExpr := psql.Select(sm.Columns( + psql.F("unnest", psql.Cast(psql.Arg(pkID), "integer[]")), + )) + + return CommsEmailLogs.Query(append(mods, + sm.Where(psql.Group(CommsEmailLogs.Columns.TemplateID).OP("IN", PKArgExpr)), + )...) +} + +func insertCommsEmailTemplateTemplateEmailLogs0(ctx context.Context, exec bob.Executor, commsEmailLogs1 []*CommsEmailLogSetter, commsEmailTemplate0 *CommsEmailTemplate) (CommsEmailLogSlice, error) { + for i := range commsEmailLogs1 { + commsEmailLogs1[i].TemplateID = omitnull.From(commsEmailTemplate0.ID) + } + + ret, err := CommsEmailLogs.Insert(bob.ToMods(commsEmailLogs1...)).All(ctx, exec) + if err != nil { + return ret, fmt.Errorf("insertCommsEmailTemplateTemplateEmailLogs0: %w", err) + } + + return ret, nil +} + +func attachCommsEmailTemplateTemplateEmailLogs0(ctx context.Context, exec bob.Executor, count int, commsEmailLogs1 CommsEmailLogSlice, commsEmailTemplate0 *CommsEmailTemplate) (CommsEmailLogSlice, error) { + setter := &CommsEmailLogSetter{ + TemplateID: omitnull.From(commsEmailTemplate0.ID), + } + + err := commsEmailLogs1.UpdateAll(ctx, exec, *setter) + if err != nil { + return nil, fmt.Errorf("attachCommsEmailTemplateTemplateEmailLogs0: %w", err) + } + + return commsEmailLogs1, nil +} + +func (commsEmailTemplate0 *CommsEmailTemplate) InsertTemplateEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLogSetter) error { + if len(related) == 0 { + return nil + } + + var err error + + commsEmailLogs1, err := insertCommsEmailTemplateTemplateEmailLogs0(ctx, exec, related, commsEmailTemplate0) + if err != nil { + return err + } + + commsEmailTemplate0.R.TemplateEmailLogs = append(commsEmailTemplate0.R.TemplateEmailLogs, commsEmailLogs1...) + + for _, rel := range commsEmailLogs1 { + rel.R.TemplateEmailTemplate = commsEmailTemplate0 + } + return nil +} + +func (commsEmailTemplate0 *CommsEmailTemplate) AttachTemplateEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLog) error { + if len(related) == 0 { + return nil + } + + var err error + commsEmailLogs1 := CommsEmailLogSlice(related) + + _, err = attachCommsEmailTemplateTemplateEmailLogs0(ctx, exec, len(related), commsEmailLogs1, commsEmailTemplate0) + if err != nil { + return err + } + + commsEmailTemplate0.R.TemplateEmailLogs = append(commsEmailTemplate0.R.TemplateEmailLogs, commsEmailLogs1...) + + for _, rel := range related { + rel.R.TemplateEmailTemplate = commsEmailTemplate0 + } + + return nil +} + +type commsEmailTemplateWhere[Q psql.Filterable] struct { + ContentHTML psql.WhereMod[Q, string] + ContentTXT psql.WhereMod[Q, string] + ContentHashHTML psql.WhereMod[Q, string] + ContentHashTXT psql.WhereMod[Q, string] + Created psql.WhereMod[Q, time.Time] + ID psql.WhereMod[Q, int32] + Superceded psql.WhereNullMod[Q, time.Time] + MessageType psql.WhereMod[Q, enums.CommsMessagetypeemail] +} + +func (commsEmailTemplateWhere[Q]) AliasedAs(alias string) commsEmailTemplateWhere[Q] { + return buildCommsEmailTemplateWhere[Q](buildCommsEmailTemplateColumns(alias)) +} + +func buildCommsEmailTemplateWhere[Q psql.Filterable](cols commsEmailTemplateColumns) commsEmailTemplateWhere[Q] { + return commsEmailTemplateWhere[Q]{ + ContentHTML: psql.Where[Q, string](cols.ContentHTML), + ContentTXT: psql.Where[Q, string](cols.ContentTXT), + ContentHashHTML: psql.Where[Q, string](cols.ContentHashHTML), + ContentHashTXT: psql.Where[Q, string](cols.ContentHashTXT), + Created: psql.Where[Q, time.Time](cols.Created), + ID: psql.Where[Q, int32](cols.ID), + Superceded: psql.WhereNull[Q, time.Time](cols.Superceded), + MessageType: psql.Where[Q, enums.CommsMessagetypeemail](cols.MessageType), + } +} + +func (o *CommsEmailTemplate) Preload(name string, retrieved any) error { + if o == nil { + return nil + } + + switch name { + case "TemplateEmailLogs": + rels, ok := retrieved.(CommsEmailLogSlice) + if !ok { + return fmt.Errorf("commsEmailTemplate cannot load %T as %q", retrieved, name) + } + + o.R.TemplateEmailLogs = rels + + for _, rel := range rels { + if rel != nil { + rel.R.TemplateEmailTemplate = o + } + } + return nil + default: + return fmt.Errorf("commsEmailTemplate has no relationship %q", name) + } +} + +type commsEmailTemplatePreloader struct{} + +func buildCommsEmailTemplatePreloader() commsEmailTemplatePreloader { + return commsEmailTemplatePreloader{} +} + +type commsEmailTemplateThenLoader[Q orm.Loadable] struct { + TemplateEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildCommsEmailTemplateThenLoader[Q orm.Loadable]() commsEmailTemplateThenLoader[Q] { + type TemplateEmailLogsLoadInterface interface { + LoadTemplateEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return commsEmailTemplateThenLoader[Q]{ + TemplateEmailLogs: thenLoadBuilder[Q]( + "TemplateEmailLogs", + func(ctx context.Context, exec bob.Executor, retrieved TemplateEmailLogsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadTemplateEmailLogs(ctx, exec, mods...) + }, + ), + } +} + +// LoadTemplateEmailLogs loads the commsEmailTemplate's TemplateEmailLogs into the .R struct +func (o *CommsEmailTemplate) LoadTemplateEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + // Reset the relationship + o.R.TemplateEmailLogs = nil + + related, err := o.TemplateEmailLogs(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, rel := range related { + rel.R.TemplateEmailTemplate = o + } + + o.R.TemplateEmailLogs = related + return nil +} + +// LoadTemplateEmailLogs loads the commsEmailTemplate's TemplateEmailLogs into the .R struct +func (os CommsEmailTemplateSlice) LoadTemplateEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + commsEmailLogs, err := os.TemplateEmailLogs(mods...).All(ctx, exec) + if err != nil { + return err + } + + for _, o := range os { + if o == nil { + continue + } + + o.R.TemplateEmailLogs = nil + } + + for _, o := range os { + if o == nil { + continue + } + + for _, rel := range commsEmailLogs { + + if !rel.TemplateID.IsValue() { + continue + } + if !(rel.TemplateID.IsValue() && o.ID == rel.TemplateID.MustGet()) { + continue + } + + rel.R.TemplateEmailTemplate = o + + o.R.TemplateEmailLogs = append(o.R.TemplateEmailLogs, rel) + } + } + + return nil +} + +// commsEmailTemplateC is where relationship counts are stored. +type commsEmailTemplateC struct { + TemplateEmailLogs *int64 +} + +// PreloadCount sets a count in the C struct by name +func (o *CommsEmailTemplate) PreloadCount(name string, count int64) error { + if o == nil { + return nil + } + + switch name { + case "TemplateEmailLogs": + o.C.TemplateEmailLogs = &count + } + return nil +} + +type commsEmailTemplateCountPreloader struct { + TemplateEmailLogs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader +} + +func buildCommsEmailTemplateCountPreloader() commsEmailTemplateCountPreloader { + return commsEmailTemplateCountPreloader{ + TemplateEmailLogs: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { + return countPreloader[*CommsEmailTemplate]("TemplateEmailLogs", func(parent string) bob.Expression { + // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) + if parent == "" { + parent = CommsEmailTemplates.Alias() + } + + subqueryMods := []bob.Mod[*dialect.SelectQuery]{ + sm.Columns(psql.Raw("count(*)")), + + sm.From(CommsEmailLogs.Name()), + sm.Where(psql.Quote(CommsEmailLogs.Alias(), "template_id").EQ(psql.Quote(parent, "id"))), + } + subqueryMods = append(subqueryMods, mods...) + return psql.Group(psql.Select(subqueryMods...).Expression) + }) + }, + } +} + +type commsEmailTemplateCountThenLoader[Q orm.Loadable] struct { + TemplateEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] +} + +func buildCommsEmailTemplateCountThenLoader[Q orm.Loadable]() commsEmailTemplateCountThenLoader[Q] { + type TemplateEmailLogsCountInterface interface { + LoadCountTemplateEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error + } + + return commsEmailTemplateCountThenLoader[Q]{ + TemplateEmailLogs: countThenLoadBuilder[Q]( + "TemplateEmailLogs", + func(ctx context.Context, exec bob.Executor, retrieved TemplateEmailLogsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { + return retrieved.LoadCountTemplateEmailLogs(ctx, exec, mods...) + }, + ), + } +} + +// LoadCountTemplateEmailLogs loads the count of TemplateEmailLogs into the C struct +func (o *CommsEmailTemplate) LoadCountTemplateEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if o == nil { + return nil + } + + count, err := o.TemplateEmailLogs(mods...).Count(ctx, exec) + if err != nil { + return err + } + + o.C.TemplateEmailLogs = &count + return nil +} + +// LoadCountTemplateEmailLogs loads the count of TemplateEmailLogs for a slice +func (os CommsEmailTemplateSlice) LoadCountTemplateEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { + if len(os) == 0 { + return nil + } + + for _, o := range os { + if err := o.LoadCountTemplateEmailLogs(ctx, exec, mods...); err != nil { + return err + } + } + + return nil +} + +type commsEmailTemplateJoins[Q dialect.Joinable] struct { + typ string + TemplateEmailLogs modAs[Q, commsEmailLogColumns] +} + +func (j commsEmailTemplateJoins[Q]) aliasedAs(alias string) commsEmailTemplateJoins[Q] { + return buildCommsEmailTemplateJoins[Q](buildCommsEmailTemplateColumns(alias), j.typ) +} + +func buildCommsEmailTemplateJoins[Q dialect.Joinable](cols commsEmailTemplateColumns, typ string) commsEmailTemplateJoins[Q] { + return commsEmailTemplateJoins[Q]{ + typ: typ, + TemplateEmailLogs: modAs[Q, commsEmailLogColumns]{ + c: CommsEmailLogs.Columns, + f: func(to commsEmailLogColumns) bob.Mod[Q] { + mods := make(mods.QueryMods[Q], 0, 1) + + { + mods = append(mods, dialect.Join[Q](typ, CommsEmailLogs.Name().As(to.Alias())).On( + to.TemplateID.EQ(cols.ID), + )) + } + + return mods + }, + }, + } +} diff --git a/db/models/comms.phone.bob.go b/db/models/comms.phone.bob.go index 185a680c..ffc12632 100644 --- a/db/models/comms.phone.bob.go +++ b/db/models/comms.phone.bob.go @@ -43,9 +43,8 @@ type CommsPhonesQuery = *psql.ViewQuery[*CommsPhone, CommsPhoneSlice] // commsPhoneR is where relationships are stored. type commsPhoneR struct { - SourceEmailLogs CommsEmailLogSlice // comms.email_log.email_log_source_fkey - DestinationTextLogs CommsTextLogSlice // comms.text_log.text_log_destination_fkey - SourceTextLogs CommsTextLogSlice // comms.text_log.text_log_source_fkey + DestinationTextLogs CommsTextLogSlice // comms.text_log.text_log_destination_fkey + SourceTextLogs CommsTextLogSlice // comms.text_log.text_log_source_fkey } func buildCommsPhoneColumns(alias string) commsPhoneColumns { @@ -372,30 +371,6 @@ func (o CommsPhoneSlice) ReloadAll(ctx context.Context, exec bob.Executor) error return nil } -// SourceEmailLogs starts a query for related objects on comms.email_log -func (o *CommsPhone) SourceEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { - return CommsEmailLogs.Query(append(mods, - sm.Where(CommsEmailLogs.Columns.Source.EQ(psql.Arg(o.E164))), - )...) -} - -func (os CommsPhoneSlice) SourceEmailLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsEmailLogsQuery { - pkE164 := make(pgtypes.Array[string], 0, len(os)) - for _, o := range os { - if o == nil { - continue - } - pkE164 = append(pkE164, o.E164) - } - PKArgExpr := psql.Select(sm.Columns( - psql.F("unnest", psql.Cast(psql.Arg(pkE164), "text[]")), - )) - - return CommsEmailLogs.Query(append(mods, - sm.Where(psql.Group(CommsEmailLogs.Columns.Source).OP("IN", PKArgExpr)), - )...) -} - // DestinationTextLogs starts a query for related objects on comms.text_log func (o *CommsPhone) DestinationTextLogs(mods ...bob.Mod[*dialect.SelectQuery]) CommsTextLogsQuery { return CommsTextLogs.Query(append(mods, @@ -444,74 +419,6 @@ func (os CommsPhoneSlice) SourceTextLogs(mods ...bob.Mod[*dialect.SelectQuery]) )...) } -func insertCommsPhoneSourceEmailLogs0(ctx context.Context, exec bob.Executor, commsEmailLogs1 []*CommsEmailLogSetter, commsPhone0 *CommsPhone) (CommsEmailLogSlice, error) { - for i := range commsEmailLogs1 { - commsEmailLogs1[i].Source = omit.From(commsPhone0.E164) - } - - ret, err := CommsEmailLogs.Insert(bob.ToMods(commsEmailLogs1...)).All(ctx, exec) - if err != nil { - return ret, fmt.Errorf("insertCommsPhoneSourceEmailLogs0: %w", err) - } - - return ret, nil -} - -func attachCommsPhoneSourceEmailLogs0(ctx context.Context, exec bob.Executor, count int, commsEmailLogs1 CommsEmailLogSlice, commsPhone0 *CommsPhone) (CommsEmailLogSlice, error) { - setter := &CommsEmailLogSetter{ - Source: omit.From(commsPhone0.E164), - } - - err := commsEmailLogs1.UpdateAll(ctx, exec, *setter) - if err != nil { - return nil, fmt.Errorf("attachCommsPhoneSourceEmailLogs0: %w", err) - } - - return commsEmailLogs1, nil -} - -func (commsPhone0 *CommsPhone) InsertSourceEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLogSetter) error { - if len(related) == 0 { - return nil - } - - var err error - - commsEmailLogs1, err := insertCommsPhoneSourceEmailLogs0(ctx, exec, related, commsPhone0) - if err != nil { - return err - } - - commsPhone0.R.SourceEmailLogs = append(commsPhone0.R.SourceEmailLogs, commsEmailLogs1...) - - for _, rel := range commsEmailLogs1 { - rel.R.SourcePhone = commsPhone0 - } - return nil -} - -func (commsPhone0 *CommsPhone) AttachSourceEmailLogs(ctx context.Context, exec bob.Executor, related ...*CommsEmailLog) error { - if len(related) == 0 { - return nil - } - - var err error - commsEmailLogs1 := CommsEmailLogSlice(related) - - _, err = attachCommsPhoneSourceEmailLogs0(ctx, exec, len(related), commsEmailLogs1, commsPhone0) - if err != nil { - return err - } - - commsPhone0.R.SourceEmailLogs = append(commsPhone0.R.SourceEmailLogs, commsEmailLogs1...) - - for _, rel := range related { - rel.R.SourcePhone = commsPhone0 - } - - return nil -} - func insertCommsPhoneDestinationTextLogs0(ctx context.Context, exec bob.Executor, commsTextLogs1 []*CommsTextLogSetter, commsPhone0 *CommsPhone) (CommsTextLogSlice, error) { for i := range commsTextLogs1 { commsTextLogs1[i].Destination = omit.From(commsPhone0.E164) @@ -670,20 +577,6 @@ func (o *CommsPhone) Preload(name string, retrieved any) error { } switch name { - case "SourceEmailLogs": - rels, ok := retrieved.(CommsEmailLogSlice) - if !ok { - return fmt.Errorf("commsPhone cannot load %T as %q", retrieved, name) - } - - o.R.SourceEmailLogs = rels - - for _, rel := range rels { - if rel != nil { - rel.R.SourcePhone = o - } - } - return nil case "DestinationTextLogs": rels, ok := retrieved.(CommsTextLogSlice) if !ok { @@ -724,15 +617,11 @@ func buildCommsPhonePreloader() commsPhonePreloader { } type commsPhoneThenLoader[Q orm.Loadable] struct { - SourceEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] DestinationTextLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] SourceTextLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] } func buildCommsPhoneThenLoader[Q orm.Loadable]() commsPhoneThenLoader[Q] { - type SourceEmailLogsLoadInterface interface { - LoadSourceEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error - } type DestinationTextLogsLoadInterface interface { LoadDestinationTextLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -741,12 +630,6 @@ func buildCommsPhoneThenLoader[Q orm.Loadable]() commsPhoneThenLoader[Q] { } return commsPhoneThenLoader[Q]{ - SourceEmailLogs: thenLoadBuilder[Q]( - "SourceEmailLogs", - func(ctx context.Context, exec bob.Executor, retrieved SourceEmailLogsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { - return retrieved.LoadSourceEmailLogs(ctx, exec, mods...) - }, - ), DestinationTextLogs: thenLoadBuilder[Q]( "DestinationTextLogs", func(ctx context.Context, exec bob.Executor, retrieved DestinationTextLogsLoadInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -762,67 +645,6 @@ func buildCommsPhoneThenLoader[Q orm.Loadable]() commsPhoneThenLoader[Q] { } } -// LoadSourceEmailLogs loads the commsPhone's SourceEmailLogs into the .R struct -func (o *CommsPhone) LoadSourceEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if o == nil { - return nil - } - - // Reset the relationship - o.R.SourceEmailLogs = nil - - related, err := o.SourceEmailLogs(mods...).All(ctx, exec) - if err != nil { - return err - } - - for _, rel := range related { - rel.R.SourcePhone = o - } - - o.R.SourceEmailLogs = related - return nil -} - -// LoadSourceEmailLogs loads the commsPhone's SourceEmailLogs into the .R struct -func (os CommsPhoneSlice) LoadSourceEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if len(os) == 0 { - return nil - } - - commsEmailLogs, err := os.SourceEmailLogs(mods...).All(ctx, exec) - if err != nil { - return err - } - - for _, o := range os { - if o == nil { - continue - } - - o.R.SourceEmailLogs = nil - } - - for _, o := range os { - if o == nil { - continue - } - - for _, rel := range commsEmailLogs { - - if !(o.E164 == rel.Source) { - continue - } - - rel.R.SourcePhone = o - - o.R.SourceEmailLogs = append(o.R.SourceEmailLogs, rel) - } - } - - return nil -} - // LoadDestinationTextLogs loads the commsPhone's DestinationTextLogs into the .R struct func (o *CommsPhone) LoadDestinationTextLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -947,7 +769,6 @@ func (os CommsPhoneSlice) LoadSourceTextLogs(ctx context.Context, exec bob.Execu // commsPhoneC is where relationship counts are stored. type commsPhoneC struct { - SourceEmailLogs *int64 DestinationTextLogs *int64 SourceTextLogs *int64 } @@ -959,8 +780,6 @@ func (o *CommsPhone) PreloadCount(name string, count int64) error { } switch name { - case "SourceEmailLogs": - o.C.SourceEmailLogs = &count case "DestinationTextLogs": o.C.DestinationTextLogs = &count case "SourceTextLogs": @@ -970,30 +789,12 @@ func (o *CommsPhone) PreloadCount(name string, count int64) error { } type commsPhoneCountPreloader struct { - SourceEmailLogs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader DestinationTextLogs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader SourceTextLogs func(...bob.Mod[*dialect.SelectQuery]) psql.Preloader } func buildCommsPhoneCountPreloader() commsPhoneCountPreloader { return commsPhoneCountPreloader{ - SourceEmailLogs: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { - return countPreloader[*CommsPhone]("SourceEmailLogs", func(parent string) bob.Expression { - // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) - if parent == "" { - parent = CommsPhones.Alias() - } - - subqueryMods := []bob.Mod[*dialect.SelectQuery]{ - sm.Columns(psql.Raw("count(*)")), - - sm.From(CommsEmailLogs.Name()), - sm.Where(psql.Quote(CommsEmailLogs.Alias(), "source").EQ(psql.Quote(parent, "e164"))), - } - subqueryMods = append(subqueryMods, mods...) - return psql.Group(psql.Select(subqueryMods...).Expression) - }) - }, DestinationTextLogs: func(mods ...bob.Mod[*dialect.SelectQuery]) psql.Preloader { return countPreloader[*CommsPhone]("DestinationTextLogs", func(parent string) bob.Expression { // Build a correlated subquery: (SELECT COUNT(*) FROM related WHERE fk = parent.pk) @@ -1032,15 +833,11 @@ func buildCommsPhoneCountPreloader() commsPhoneCountPreloader { } type commsPhoneCountThenLoader[Q orm.Loadable] struct { - SourceEmailLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] DestinationTextLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] SourceTextLogs func(...bob.Mod[*dialect.SelectQuery]) orm.Loader[Q] } func buildCommsPhoneCountThenLoader[Q orm.Loadable]() commsPhoneCountThenLoader[Q] { - type SourceEmailLogsCountInterface interface { - LoadCountSourceEmailLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error - } type DestinationTextLogsCountInterface interface { LoadCountDestinationTextLogs(context.Context, bob.Executor, ...bob.Mod[*dialect.SelectQuery]) error } @@ -1049,12 +846,6 @@ func buildCommsPhoneCountThenLoader[Q orm.Loadable]() commsPhoneCountThenLoader[ } return commsPhoneCountThenLoader[Q]{ - SourceEmailLogs: countThenLoadBuilder[Q]( - "SourceEmailLogs", - func(ctx context.Context, exec bob.Executor, retrieved SourceEmailLogsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { - return retrieved.LoadCountSourceEmailLogs(ctx, exec, mods...) - }, - ), DestinationTextLogs: countThenLoadBuilder[Q]( "DestinationTextLogs", func(ctx context.Context, exec bob.Executor, retrieved DestinationTextLogsCountInterface, mods ...bob.Mod[*dialect.SelectQuery]) error { @@ -1070,36 +861,6 @@ func buildCommsPhoneCountThenLoader[Q orm.Loadable]() commsPhoneCountThenLoader[ } } -// LoadCountSourceEmailLogs loads the count of SourceEmailLogs into the C struct -func (o *CommsPhone) LoadCountSourceEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if o == nil { - return nil - } - - count, err := o.SourceEmailLogs(mods...).Count(ctx, exec) - if err != nil { - return err - } - - o.C.SourceEmailLogs = &count - return nil -} - -// LoadCountSourceEmailLogs loads the count of SourceEmailLogs for a slice -func (os CommsPhoneSlice) LoadCountSourceEmailLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { - if len(os) == 0 { - return nil - } - - for _, o := range os { - if err := o.LoadCountSourceEmailLogs(ctx, exec, mods...); err != nil { - return err - } - } - - return nil -} - // LoadCountDestinationTextLogs loads the count of DestinationTextLogs into the C struct func (o *CommsPhone) LoadCountDestinationTextLogs(ctx context.Context, exec bob.Executor, mods ...bob.Mod[*dialect.SelectQuery]) error { if o == nil { @@ -1162,7 +923,6 @@ func (os CommsPhoneSlice) LoadCountSourceTextLogs(ctx context.Context, exec bob. type commsPhoneJoins[Q dialect.Joinable] struct { typ string - SourceEmailLogs modAs[Q, commsEmailLogColumns] DestinationTextLogs modAs[Q, commsTextLogColumns] SourceTextLogs modAs[Q, commsTextLogColumns] } @@ -1174,20 +934,6 @@ func (j commsPhoneJoins[Q]) aliasedAs(alias string) commsPhoneJoins[Q] { func buildCommsPhoneJoins[Q dialect.Joinable](cols commsPhoneColumns, typ string) commsPhoneJoins[Q] { return commsPhoneJoins[Q]{ typ: typ, - SourceEmailLogs: modAs[Q, commsEmailLogColumns]{ - c: CommsEmailLogs.Columns, - f: func(to commsEmailLogColumns) bob.Mod[Q] { - mods := make(mods.QueryMods[Q], 0, 1) - - { - mods = append(mods, dialect.Join[Q](typ, CommsEmailLogs.Name().As(to.Alias())).On( - to.Source.EQ(cols.E164), - )) - } - - return mods - }, - }, DestinationTextLogs: modAs[Q, commsTextLogColumns]{ c: CommsTextLogs.Columns, f: func(to commsTextLogColumns) bob.Mod[Q] { diff --git a/main.go b/main.go index 4b73dfac..ed8956b6 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "github.com/Gleipnir-Technology/nidus-sync/auth" "github.com/Gleipnir-Technology/nidus-sync/background" + "github.com/Gleipnir-Technology/nidus-sync/comms/email" "github.com/Gleipnir-Technology/nidus-sync/config" "github.com/Gleipnir-Technology/nidus-sync/db" "github.com/Gleipnir-Technology/nidus-sync/public-report" @@ -39,6 +40,12 @@ func main() { os.Exit(2) } + err = email.LoadTemplates() + if err != nil { + log.Error().Err(err).Msg("Failed to load email templates") + os.Exit(3) + } + router_logger := log.With().Logger() r := chi.NewRouter() diff --git a/public-report/email.go b/public-report/email.go index e39d9de0..823a30fd 100644 --- a/public-report/email.go +++ b/public-report/email.go @@ -1,17 +1,18 @@ package publicreport import ( + "fmt" "net/http" - "github.com/Gleipnir-Technology/nidus-sync/comms" + //"github.com/Gleipnir-Technology/nidus-sync/comms/email" "github.com/go-chi/chi/v5" ) -func getEmailInitial(w http.ResponseWriter, r *http.Request) { - email := chi.URLParam(r, "email") - comms.RenderEmailInitial(w, email) -} -func getEmailReportSubscriptionConfirmation(w http.ResponseWriter, r *http.Request) { - report_id := chi.URLParam(r, "report_id") - comms.RenderEmailReportConfirmation(w, report_id) +func getEmailByCode(w http.ResponseWriter, r *http.Request) { + code := chi.URLParam(r, "code") + if code == "" { + http.Error(w, "You must specify a code", http.StatusBadRequest) + return + } + fmt.Fprintf(w, "Pretend email contet for %s", code) } diff --git a/public-report/quick.go b/public-report/quick.go index 0c344f41..c8d94c32 100644 --- a/public-report/quick.go +++ b/public-report/quick.go @@ -258,7 +258,7 @@ func postRegisterNotifications(w http.ResponseWriter, r *http.Request) { return } if email != "" { - background.ReportSubscriptionConfirmationEmail(email) + background.ReportSubscriptionConfirmationEmail(email, report_id) } if phone_str != "" { background.ReportSubscriptionConfirmationText(*phone, report_id) diff --git a/public-report/routes.go b/public-report/routes.go index 5fefd950..2c757748 100644 --- a/public-report/routes.go +++ b/public-report/routes.go @@ -10,8 +10,7 @@ func Router() chi.Router { r.Get("/", getRoot) r.Get("/privacy", getPrivacy) r.Get("/robots.txt", getRobots) - r.Get("/email/initial", getEmailInitial) - r.Get("/email/report/{report_id}/subscription-confirmation", getEmailReportSubscriptionConfirmation) + r.Get("/email", getEmailByCode) r.Get("/image/{uuid}", getImageByUUID) r.Get("/nuisance", getNuisance) r.Post("/nuisance-submit", postNuisance)