package models import ( "fmt" "io" "strconv" "github.com/stashapp/stash/pkg/sliceutil" "github.com/stashapp/stash/pkg/sliceutil/intslice" ) type RelationshipUpdateMode string const ( RelationshipUpdateModeSet RelationshipUpdateMode = "SET" RelationshipUpdateModeAdd RelationshipUpdateMode = "ADD" RelationshipUpdateModeRemove RelationshipUpdateMode = "REMOVE" ) var AllRelationshipUpdateMode = []RelationshipUpdateMode{ RelationshipUpdateModeSet, RelationshipUpdateModeAdd, RelationshipUpdateModeRemove, } func (e RelationshipUpdateMode) IsValid() bool { switch e { case RelationshipUpdateModeSet, RelationshipUpdateModeAdd, RelationshipUpdateModeRemove: return true } return false } func (e RelationshipUpdateMode) String() string { return string(e) } func (e *RelationshipUpdateMode) UnmarshalGQL(v interface{}) error { str, ok := v.(string) if !ok { return fmt.Errorf("enums must be strings") } *e = RelationshipUpdateMode(str) if !e.IsValid() { return fmt.Errorf("%s is not a valid RelationshipUpdateMode", str) } return nil } func (e RelationshipUpdateMode) MarshalGQL(w io.Writer) { fmt.Fprint(w, strconv.Quote(e.String())) } type UpdateIDs struct { IDs []int `json:"ids"` Mode RelationshipUpdateMode `json:"mode"` } func (u *UpdateIDs) IDStrings() []string { if u == nil { return nil } return intslice.IntSliceToStringSlice(u.IDs) } // GetImpactedIDs returns the IDs that will be impacted by the update. // If the update is to add IDs, then the impacted IDs are the IDs being added. // If the update is to remove IDs, then the impacted IDs are the IDs being removed. // If the update is to set IDs, then the impacted IDs are the IDs being removed and the IDs being added. // Any IDs that are already present and are being added are not returned. // Likewise, any IDs that are not present that are being removed are not returned. func (u *UpdateIDs) ImpactedIDs(existing []int) []int { if u == nil { return nil } switch u.Mode { case RelationshipUpdateModeAdd: return sliceutil.Exclude(u.IDs, existing) case RelationshipUpdateModeRemove: return sliceutil.Intersect(existing, u.IDs) case RelationshipUpdateModeSet: // get the difference between the two lists return sliceutil.NotIntersect(existing, u.IDs) } return nil } // Apply applies the update to a list of existing ids, returning the result. func (u *UpdateIDs) Apply(existing []int) []int { if u == nil { return existing } return applyUpdate(u.IDs, u.Mode, existing) } type UpdateStrings struct { Values []string `json:"values"` Mode RelationshipUpdateMode `json:"mode"` } func (u *UpdateStrings) Strings() []string { if u == nil { return nil } return u.Values } // Apply applies the update to a list of existing strings, returning the result. func (u *UpdateStrings) Apply(existing []string) []string { if u == nil { return existing } return applyUpdate(u.Values, u.Mode, existing) } // applyUpdate applies values to existing, using the update mode specified. func applyUpdate[T comparable](values []T, mode RelationshipUpdateMode, existing []T) []T { switch mode { case RelationshipUpdateModeAdd: return sliceutil.AppendUniques(existing, values) case RelationshipUpdateModeRemove: return sliceutil.Exclude(existing, values) case RelationshipUpdateModeSet: return values } return nil }