models: Changed change logging system to be allow for better querying in the future.
the build was successful

This commit is contained in:
2018-10-28 12:18:17 +01:00
parent 9affdbd20e
commit cee370c2ac
13 changed files with 224 additions and 25 deletions
+13 -5
View File
@@ -4,17 +4,25 @@ import "time"
// Change represents a change in the rpdata history through the API.
type Change struct {
ID string `bson:"_id"`
Model string `bson:"model"`
Op string `bson:"op"`
Author string `bson:"author"`
Date time.Time `bson:"date"`
ID string `bson:"_id"`
Model string `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"`
Posts []Post `bson:"posts"`
}
// ChangeKey is a key for a change that can be used when subscribing to them.
type ChangeKey struct {
Model string `bson:"model"`
ID string `bson:"id"`
}
// Data makes a combined, mixed array of all the models stored in this change.
func (change *Change) Data() []interface{} {
data := make([]interface{}, 0, len(change.Logs)+len(change.Characters)+len(change.Posts))
+8
View File
@@ -0,0 +1,8 @@
package changekeys
import "git.aiterp.net/rpdata/api/models"
// All makes a changelog that's (model, "*"). It's a helper to standardize it.
func All(model string) models.ChangeKey {
return models.ChangeKey{Model: model, ID: "*"}
}
+10
View File
@@ -0,0 +1,10 @@
package changekeys
import "git.aiterp.net/rpdata/api/models"
// Listed is a helper for cases like []models.ChangeKey{changekeys.All("Logs"), changekeys.One(log)}
func Listed(object interface{}) []models.ChangeKey {
key := One(object)
return []models.ChangeKey{key, All(key.Model)}
}
+27
View File
@@ -0,0 +1,27 @@
package changekeys
import (
"reflect"
"git.aiterp.net/rpdata/api/models"
)
// Many returns a key set matching the input objects, but without the asterisk key. You may pass
// a slice as an argument, for example (log, posts) and it will be flattened
func Many(objects ...interface{}) []models.ChangeKey {
keys := make([]models.ChangeKey, 0, len(objects))
for _, object := range objects {
if v := reflect.ValueOf(object); v.Kind() == reflect.Slice {
elems := make([]interface{}, 0, v.Len())
for i := 0; i < v.Len(); i++ {
elems = append(elems, v.Index(i).Interface())
}
keys = append(keys, Many(elems...)...)
} else {
keys = append(keys, One(object))
}
}
return keys
}
+52
View File
@@ -0,0 +1,52 @@
package changekeys_test
import (
"testing"
"git.aiterp.net/rpdata/api/models/changekeys"
"git.aiterp.net/rpdata/api/models"
)
func TestMany(t *testing.T) {
data := []interface{}{
models.Log{ID: "Stuff"},
[]interface{}{
models.Post{ID: "P1"},
models.Post{ID: "P2"},
models.Post{ID: "P3"},
[]interface{}{
models.Post{ID: "P4"},
models.Character{ID: "C17"},
models.Channel{Name: "#Stuff"},
},
},
models.Post{ID: "P5"},
}
expectations := []models.ChangeKey{
{Model: "Log", ID: "Stuff"},
{Model: "Post", ID: "P1"},
{Model: "Post", ID: "P2"},
{Model: "Post", ID: "P3"},
{Model: "Post", ID: "P4"},
{Model: "Character", ID: "C17"},
{Model: "Channel", ID: "#Stuff"},
{Model: "Post", ID: "P5"},
}
results := changekeys.Many(data...)
if len(results) != len(expectations) {
t.Fatal("Incorrect result length")
}
for i := range expectations {
result := results[i]
expectation := expectations[i]
if result.ID != expectation.ID || result.Model != expectation.Model {
t.Errorf("Incorrect: actual(%#+v, %#+v) != expected(%#+v, %#+v)", result.Model, result.ID, expectation.Model, expectation.ID)
}
}
}
+29
View File
@@ -0,0 +1,29 @@
package changekeys
import (
"reflect"
"git.aiterp.net/rpdata/api/models"
)
// One makes a ChangeKey for a model, or panics if it's not supported.
func One(object interface{}) models.ChangeKey {
model := ""
if t := reflect.TypeOf(object); t.Kind() == reflect.Ptr {
model = t.Elem().Name()
} else {
model = t.Name()
}
id := ""
v := reflect.ValueOf(object)
if f := v.FieldByName("ID"); f.Kind() == reflect.String {
id = f.String()
} else if f = v.FieldByName("Name"); f.Kind() == reflect.String {
id = f.String()
} else {
panic("Unsupported model")
}
return models.ChangeKey{Model: model, ID: id}
}
+42
View File
@@ -0,0 +1,42 @@
package changekeys_test
import (
"testing"
"git.aiterp.net/rpdata/api/models"
"git.aiterp.net/rpdata/api/models/changekeys"
)
func TestOne(t *testing.T) {
table := []struct {
Label string
Input interface{}
Output models.ChangeKey
}{
{
"Character_C17",
models.Character{ID: "C17"},
models.ChangeKey{Model: "Character", ID: "C17"},
},
{
"Channel_#Miner'sRespite",
models.Channel{Name: "#Miner'sRespite"},
models.ChangeKey{Model: "Channel", ID: "#Miner'sRespite"},
},
{
"Log_2018-10-23_210303325_RedrockAgency",
models.Log{ID: "2018-10-23_210303325_RedrockAgency", ShortID: "L807"},
models.ChangeKey{Model: "Log", ID: "2018-10-23_210303325_RedrockAgency"},
},
}
for _, row := range table {
t.Run(row.Label, func(t *testing.T) {
key := changekeys.One(row.Input)
if key.ID != row.Output.ID || key.Model != row.Output.Model {
t.Errorf("Incorrect: actual(%#+v, %#+v) != expected(%#+v, %#+v)", key.Model, key.ID, row.Output.Model, row.Output.ID)
}
})
}
}
+1
View File
@@ -18,6 +18,7 @@ func init() {
collection.EnsureIndexKey("date")
collection.EnsureIndexKey("author")
collection.EnsureIndexKey("keys")
err := collection.EnsureIndex(mgo.Index{
Name: "expiry",
+10 -2
View File
@@ -8,8 +8,8 @@ import (
"git.aiterp.net/rpdata/api/models"
)
// Submit a change to the database
func Submit(model, op, author string, objects ...interface{}) (models.Change, error) {
// Submit a change to the database. The objects may be any supported model, or arrays.
func Submit(model, op, author string, listed bool, keys []models.ChangeKey, objects ...interface{}) (models.Change, error) {
submitMutex.Lock()
defer submitMutex.Unlock()
@@ -24,16 +24,24 @@ func Submit(model, op, author string, objects ...interface{}) (models.Change, er
Date: time.Now(),
Op: op,
Author: author,
Keys: keys,
Listed: listed,
}
for _, object := range objects {
switch object := object.(type) {
case models.Log:
change.Logs = append(change.Logs, object)
case []models.Log:
change.Logs = append(change.Logs, object...)
case models.Character:
change.Characters = append(change.Characters, object)
case []models.Character:
change.Characters = append(change.Characters, object...)
case models.Post:
change.Posts = append(change.Posts, object)
case []models.Post:
change.Posts = append(change.Posts, object...)
}
}