GraphQL API and utilities for the rpdata project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

171 lines
4.1 KiB

package models
import (
"reflect"
"time"
)
// Change represents a change in the rpdata history through the API.
type Change struct {
ID string `bson:"_id"`
Model ChangeModel `bson:"model"`
Op string `bson:"op"`
Author string `bson:"author"`
Listed bool `bson:"listed"`
Keys []ChangeKey `bson:"keys"`
Date time.Time `bson:"date"`
Logs []*Log `bson:"logs"`
Characters []*Character `bson:"characters"`
Channels []*Channel `bson:"channels"`
Posts []*Post `bson:"posts"`
Stories []*Story `bson:"stories"`
Tags []*Tag `bson:"tags"`
Chapters []*Chapter `bson:"chapters"`
Comments []*Comment `bson:"comments"`
}
// AddObject adds the model into the appropriate array.
func (change *Change) AddObject(object interface{}) bool {
if v := reflect.ValueOf(object); v.Kind() != reflect.Ptr && v.Kind() != reflect.Slice {
return change.AddObject(v.Addr().Interface())
}
switch object := object.(type) {
case *Log:
change.Logs = append(change.Logs, object)
case []*Log:
change.Logs = append(change.Logs, object...)
case *Character:
change.Characters = append(change.Characters, object)
case []*Character:
change.Characters = append(change.Characters, object...)
case *Channel:
change.Channels = append(change.Channels, object)
case []*Channel:
change.Channels = append(change.Channels, object...)
case *Post:
change.Posts = append(change.Posts, object)
case []*Post:
change.Posts = append(change.Posts, object...)
case *Story:
change.Stories = append(change.Stories, object)
case []*Story:
change.Stories = append(change.Stories, object...)
case *Tag:
change.Tags = append(change.Tags, object)
case []*Tag:
change.Tags = append(change.Tags, object...)
case *Chapter:
change.Chapters = append(change.Chapters, object)
case []*Chapter:
change.Chapters = append(change.Chapters, object...)
case *Comment:
change.Comments = append(change.Comments, object)
case []*Comment:
change.Comments = append(change.Comments, object...)
default:
return false
}
return true
}
// Objects makes a combined, mixed array of all the models stored in this change.
func (change *Change) Objects() []interface{} {
data := make([]interface{}, 0, 8)
for _, log := range change.Logs {
data = append(data, &log)
}
for _, channel := range change.Channels {
data = append(data, &channel)
}
for _, character := range change.Characters {
data = append(data, &character)
}
for _, post := range change.Posts {
data = append(data, &post)
}
for _, story := range change.Stories {
data = append(data, &story)
}
for _, tag := range change.Tags {
data = append(data, &tag)
}
for _, chapter := range change.Chapters {
data = append(data, &chapter)
}
for _, comment := range change.Comments {
data = append(data, &comment)
}
return data
}
func (change *Change) PassesFilter(filter ChangeFilter) bool {
if filter.Author != nil && change.Author != *filter.Author {
return false
}
// For unlisted changes, pass it only if the filter refers to the specific index.
if !change.Listed {
hasSpecificKey := false
KeyFindLoop:
for _, key := range filter.Keys {
if key.ID == "*" {
continue
}
for _, changeKey := range change.Keys {
if changeKey.Model == key.Model && changeKey.ID == key.ID {
hasSpecificKey = true
break KeyFindLoop
}
}
}
if !hasSpecificKey {
return false
}
}
if filter.EarliestDate != nil && filter.EarliestDate.Before(change.Date) {
return false
}
if len(filter.Keys) > 0 {
foundKey := false
KeyFindLoop2:
for _, key := range filter.Keys {
for _, changeKey := range change.Keys {
if changeKey == key {
foundKey = true
break KeyFindLoop2
}
}
}
if !foundKey {
return false
}
}
return true
}
// ChangeKey is a key for a change that can be used when subscribing to them.
type ChangeKey struct {
Model ChangeModel `bson:"model"`
ID string `bson:"id"`
}
// ChangeFilter is a filter for listing changes.
type ChangeFilter struct {
Keys []ChangeKey
EarliestDate *time.Time
Author *string
Limit *int
}