Skip to content

Instantly share code, notes, and snippets.

@andizzle
Created March 21, 2018 05:59
Show Gist options
  • Save andizzle/d46b5ff8f740072510baf9686ca0bdff to your computer and use it in GitHub Desktop.
Save andizzle/d46b5ff8f740072510baf9686ca0bdff to your computer and use it in GitHub Desktop.
package cmds
import (
"context"
"encoding/json"
"errors"
"fmt"
"strings"
d "github.com/opensimsim/utilities/database"
)
type UpdateCertificateRequirementByIDCmd struct {
db d.SQLDb
id string
companyID string
name *string
mandatory *bool
expires *bool
groupType *GroupType
subscribers *[]ListItem
groups *[]ListItem
reminders *[]int
desiredGroups map[string]ListItem
}
func (cmd *UpdateCertificateRequirementByIDCmd) CertUpdateValidate() error {
//Perform validation
if cmd.name != nil {
_name := strings.TrimSpace(*cmd.name)
if _name == "" {
return errors.New("the name must not be empty")
}
cmd.name = &_name
}
//Remove duplicates from reminders
if cmd.reminders != nil {
_reminders := removeDuplicates(*cmd.reminders)
if len(_reminders) == 0 {
return errors.New("reminders must have at least 1 unique value")
}
cmd.reminders = &_reminders
}
// //Remove duplicates from subscribers
if cmd.subscribers != nil {
if len(*cmd.subscribers) == 0 {
return errors.New("subscribers must have at least 1 unique value")
}
}
if cmd.groups != nil {
if len(*cmd.groups) == 0 {
return errors.New("groups must have at least 1 unique value")
}
for _, g := range *cmd.groups {
cmd.desiredGroups[g.ID] = g
}
}
return nil
}
// NewUpdateCertificateRequirementCmd - Create a UpdateCertificateRequirementCmd Command
func NewUpdateCertificateRequirementByIDCmd(db d.SQLDb, id, companyID string, name *string, mandatory, expires *bool, groupType *GroupType, groups *[]ListItem, subscribers *[]ListItem, reminders *[]int) (*UpdateCertificateRequirementByIDCmd, error) {
cmd := &UpdateCertificateRequirementByIDCmd{
db: db,
id: id,
companyID: companyID,
name: name,
mandatory: mandatory,
expires: expires,
groupType: groupType,
reminders: reminders,
groups: groups,
subscribers: subscribers,
}
if err := cmd.CertUpdateValidate(); err != nil {
return nil, err
}
return cmd, nil
}
func (cmd *UpdateCertificateRequirementByIDCmd) syncReqGroup(ctx context.Context, tx d.SQLTx) error {
//Determine which items to delete
deleteIDs := []interface{}{}
stmt2 := `
SELECT id,
perspective_id,
perspective_type
FROM cert_req_group
WHERE cert_req_id = ?
`
currentGroups, err := fetchCurrentGroups(ctx, tx, stmt2, cmd.id)
if err != nil {
return err
}
for id, group := range currentGroups {
if _, ok := cmd.desiredGroups[id]; !ok {
// add to delete id list
deleteIDs = append(deleteIDs, group.PK)
} else {
delete(cmd.desiredGroups, id)
}
}
if len(deleteIDs) > 0 {
err = batchDelete(ctx, tx, "cert_req_group", "id",&[]string{"cert_req_id"}[0], &cmd.id, deleteIDs...)
}
if len(cmd.desiredGroups) > 0 {
}
return nil
}
//stmt must include the the entire where statement without placeholders
func fetchCurrentGroups(ctx context.Context, tx d.SQLCommon, stmt string, params ...interface{}) (map[string]listItemPK, error) {
rows, err := tx.QueryContext(ctx, stmt, params...)
if err != nil {
return nil, err
}
defer rows.Close()
currentGroups := map[string]listItemPK{}
for rows.Next() {
var g listItemPK
if err := rows.Scan(&g.PK, &g.ID, &g.Type); err != nil {
return nil, err
}
currentGroups[g.ID] = g
}
if err := rows.Err(); err != nil {
return nil, err
}
return currentGroups, nil
}
// Handle - is the command handler for UpdateCertificateRequirementCmd
func (cmd *UpdateCertificateRequirementByIDCmd) Handle(ctx context.Context) error {
tx, err := cmd.db.BeginTx(ctx, nil)
if err != nil {
return nil
}
err = cmd.UpdateCert(ctx, tx)
//Update Groups
if cmd.groups != nil {
stmt2 := `
SELECT id,
perspective_id,
perspective_type
FROM cert_req_group
WHERE cert_req_id = ?
`
currentGroups, err := fetchCurrentItems(ctx, tx, stmt2, cmd.id)
if err != nil {
tx.Rollback()
return err
}
desiredGroups := *cmd.groups
//Determine which items to delete
deleteIDs := []interface{}{}
// If an item is in current, but not in desired, then delete using PK
OUTER1:
for _, v := range currentGroups {
currentID := v.ID
//Search for currentID in desiredGroups
for _, j := range desiredGroups {
if j.ID == currentID {
continue OUTER1
}
}
deleteIDs = append(deleteIDs, v.PK)
}
//Perform batch delete
ownerFieldName := "cert_req_id"
err = batchDelete(ctx, tx, "cert_req_group", "id", &ownerFieldName, &cmd.id, deleteIDs...)
if err != nil {
tx.Rollback()
return err
}
//Determine which items to add
insertIDs := []ListItem{}
OUTER2:
for _, v := range desiredGroups {
desiredID := v.ID
//Search for desiredID in currentGroups
for _, j := range currentGroups {
if j.ID == desiredID {
continue OUTER2
}
}
insertIDs = append(insertIDs, ListItem{
ID: desiredID,
Type: v.Type,
})
}
//Perform batch insert
if len(insertIDs) != 0 {
stmt := d.BulkInsert("cert_req_group", []string{"cert_req_id", "perspective_id", "perspective_type"}, len(insertIDs))
insertData := []interface{}{}
for _, v := range insertIDs {
insertData = append(insertData, cmd.id, v.ID, v.Type)
}
_, err := tx.ExecContext(ctx, stmt, insertData...)
if err != nil {
tx.Rollback()
return err
}
}
}
//Update Reminders
if cmd.reminders != nil {
currentReminderDays, err := fetchCurrentReminderDays(ctx, tx, cmd.id)
if err != nil {
tx.Rollback()
return err
}
desiredReminderDays := *cmd.reminders
//Determine which items to delete
deleteIDs := []interface{}{}
// If an item is in current, but not in desired, then delete using PK
OUTER3:
for _, v := range currentReminderDays {
currentDay := v.OffsetDay
//Search for currentDay in desiredReminderDays
for _, j := range desiredReminderDays {
if j == currentDay {
continue OUTER3
}
}
deleteIDs = append(deleteIDs, v.PK)
}
//Perform batch delete
ownerFieldName := "cert_req_id"
err = batchDelete(ctx, tx, "cert_req_reminders", "id", &ownerFieldName, &cmd.id, deleteIDs...)
if err != nil {
tx.Rollback()
return err
}
//Determine which items to add
insertDays := []int{}
OUTER4:
for _, desiredDay := range desiredReminderDays {
//Search for desiredDay in currentReminderDays
for _, j := range currentReminderDays {
if j.OffsetDay == desiredDay {
continue OUTER4
}
}
insertDays = append(insertDays, desiredDay)
}
//Perform batch insert
if len(insertDays) != 0 {
stmt := d.BulkInsert("cert_req_reminders", []string{"cert_req_id", "offset_day"}, len(insertDays))
insertData := []interface{}{}
for _, day := range insertDays {
insertData = append(insertData, cmd.id, day)
}
_, err := tx.ExecContext(ctx, stmt, insertData...)
if err != nil {
tx.Rollback()
return err
}
}
}
return tx.Commit()
}
// UpdateCert update the cert itself
func (cmd *UpdateCertificateRequirementByIDCmd) UpdateCert(ctx context.Context, tx d.SQLTx) error {
//Update fields in the `cert_reqs` table
fields := map[string]interface{}{}
if cmd.name != nil {
fields["name"] = *cmd.name
}
if cmd.mandatory != nil {
var val int
if *cmd.mandatory {
val = 1
} else {
val = 0
}
fields["mandatory"] = val
}
if cmd.expires != nil {
var val int
if *cmd.expires {
val = 1
} else {
val = 0
}
fields["expires"] = val
}
if cmd.groupType != nil {
fields["group_type"] = *cmd.groupType
}
if cmd.subscribers != nil {
_nl, err := json.Marshal(*cmd.subscribers)
if err != nil {
return err
}
nl := string(_nl)
fields["sdata"] = nl
}
if len(fields) > 0 {
var updateFields string
vals := []interface{}{}
for col, val := range fields {
updateFields += fmt.Sprintf("%s = ?,", col)
vals = append(vals, val)
}
updateFields = strings.TrimRight(updateFields, ",")
vals = append(vals, cmd.id)
stmt := fmt.Sprintf("UPDATE cert_reqs SET %s WHERE id = ?;", updateFields)
_, err := tx.ExecContext(ctx, stmt, vals...)
if err != nil {
return err
}
}
return nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment