impl entities and test
parent
64772166cc
commit
468e5bedd5
|
|
@ -11,6 +11,8 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||||
"gopkg.in/mgo.v2/bson"
|
"gopkg.in/mgo.v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,12 +22,30 @@ type shortEntity struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rest *REST) entities(w http.ResponseWriter, r *http.Request) {
|
func (rest *REST) entities(w http.ResponseWriter, r *http.Request) {
|
||||||
if scope, err := rest.entityScope(r); err != nil {
|
scope, err := rest.entityScope(r)
|
||||||
|
if err != nil {
|
||||||
rest.respNotFound(w)
|
rest.respNotFound(w)
|
||||||
return
|
return
|
||||||
} else if r.Method != http.MethodGet && len(scope) > 1 {
|
}
|
||||||
|
if r.Method == http.MethodGet {
|
||||||
|
} else if r.Method == http.MethodPost && len(scope) != 0 {
|
||||||
|
rest.respNotFound(w)
|
||||||
|
return
|
||||||
|
} else if len(scope) > 1 {
|
||||||
|
if r.Method == http.MethodDelete {
|
||||||
|
q := r.URL.Query()
|
||||||
|
q.Set("delete", "")
|
||||||
|
r.URL.RawQuery = q.Encode()
|
||||||
|
}
|
||||||
r.Method = http.MethodPatch
|
r.Method = http.MethodPatch
|
||||||
}
|
}
|
||||||
|
if r.Method == http.MethodPatch && len(scope) == 1 {
|
||||||
|
r.Method = http.MethodPut
|
||||||
|
}
|
||||||
|
if r.Method == http.MethodPatch && len(scope) == 0 {
|
||||||
|
rest.respNotFound(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
switch r.Method {
|
switch r.Method {
|
||||||
case http.MethodPut:
|
case http.MethodPut:
|
||||||
rest.entitiesReplace(w, r)
|
rest.entitiesReplace(w, r)
|
||||||
|
|
@ -44,17 +64,17 @@ func (rest *REST) entities(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
func (rest *REST) entitiesCreate(w http.ResponseWriter, r *http.Request) {
|
func (rest *REST) entitiesCreate(w http.ResponseWriter, r *http.Request) {
|
||||||
scope := rest.scope(r)
|
scope := rest.scope(r)
|
||||||
entityScope, _ := rest.entityScope(r)
|
|
||||||
one, err := rest.entityParse(r.Body)
|
one, err := rest.entityParse(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rest.respBadRequest(w, err.Error())
|
rest.respBadRequest(w, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
one.ID = entityScope[0]
|
one.ID = uuid.New().String()
|
||||||
if err := rest.g.Insert(r.Context(), scope.Namespace, one); err != nil {
|
if err := rest.g.Insert(r.Context(), scope.Namespace, one); err != nil {
|
||||||
rest.respError(w, err)
|
rest.respError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
r.URL.Path += "/" + one.ID
|
||||||
rest.entitiesGet(w, r)
|
rest.entitiesGet(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -71,7 +91,7 @@ func (rest *REST) entitiesGet(w http.ResponseWriter, r *http.Request) {
|
||||||
entityScope, _ := rest.entityScope(r)
|
entityScope, _ := rest.entityScope(r)
|
||||||
switch len(entityScope) {
|
switch len(entityScope) {
|
||||||
case 0:
|
case 0:
|
||||||
rest.entitiesList(w, r)
|
rest.entitiesGetN(w, r)
|
||||||
case 1:
|
case 1:
|
||||||
rest.entitiesGetOne(w, r)
|
rest.entitiesGetOne(w, r)
|
||||||
default:
|
default:
|
||||||
|
|
@ -87,6 +107,11 @@ func (rest *REST) entitiesGetOne(w http.ResponseWriter, r *http.Request) {
|
||||||
rest.respNotFound(w)
|
rest.respNotFound(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if _, ok := r.URL.Query()["light"]; !ok {
|
||||||
|
log.Println("TODO need to get all connections")
|
||||||
|
//http.Error(w, "not impl", http.StatusNotImplemented)
|
||||||
|
//return
|
||||||
|
}
|
||||||
rest.respMap(w, entityScope[0], one)
|
rest.respMap(w, entityScope[0], one)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +153,7 @@ func (rest *REST) entitiesGetOneSub(w http.ResponseWriter, r *http.Request) {
|
||||||
rest.respMap(w, scope.EntityID, m[entityScope[0]])
|
rest.respMap(w, scope.EntityID, m[entityScope[0]])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rest *REST) entitiesList(w http.ResponseWriter, r *http.Request) {
|
func (rest *REST) entitiesGetN(w http.ResponseWriter, r *http.Request) {
|
||||||
scope := rest.scope(r)
|
scope := rest.scope(r)
|
||||||
entities, err := rest.g.List(r.Context(), scope.Namespace)
|
entities, err := rest.g.List(r.Context(), scope.Namespace)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -163,9 +188,44 @@ func (rest *REST) entitiesReplace(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rest *REST) entitiesUpdate(w http.ResponseWriter, r *http.Request) {
|
func (rest *REST) entitiesUpdate(w http.ResponseWriter, r *http.Request) {
|
||||||
log.Println(r.Method)
|
entityScope, _ := rest.entityScope(r)
|
||||||
log.Println(rest.entityScope(r))
|
scope := rest.scope(r)
|
||||||
http.Error(w, "not impl", http.StatusNotImplemented)
|
|
||||||
|
_, del := r.URL.Query()["delete"]
|
||||||
|
|
||||||
|
var m interface{}
|
||||||
|
if !del {
|
||||||
|
err := json.NewDecoder(r.Body).Decode(&m)
|
||||||
|
if err != nil {
|
||||||
|
rest.respBadRequest(w, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if mm, ok := m.(primitive.M); ok {
|
||||||
|
delete(mm, entity.ID)
|
||||||
|
m = mm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key := strings.Join(entityScope[1:], ".")
|
||||||
|
var operation interface{}
|
||||||
|
operation = operator.Set{Key: key, Value: m}
|
||||||
|
if del {
|
||||||
|
operation = operator.Unset(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := rest.g.Update(
|
||||||
|
r.Context(),
|
||||||
|
scope.Namespace,
|
||||||
|
bson.M{entity.ID: scope.EntityID},
|
||||||
|
operation,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
rest.respError(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
r.URL.Path = path.Join("/", scope.EntityID)
|
||||||
|
rest.entitiesGet(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rest *REST) entityParse(r io.Reader) (entity.One, error) {
|
func (rest *REST) entityParse(r io.Reader) (entity.One, error) {
|
||||||
|
|
@ -177,7 +237,7 @@ func (rest *REST) entityParse(r io.Reader) (entity.One, error) {
|
||||||
func (rest *REST) entityScope(r *http.Request) ([]string, error) {
|
func (rest *REST) entityScope(r *http.Request) ([]string, error) {
|
||||||
p := r.URL.Path
|
p := r.URL.Path
|
||||||
if path.Dir(p) == path.Base(p) {
|
if path.Dir(p) == path.Base(p) {
|
||||||
if r.Method == http.MethodGet {
|
if r.Method == http.MethodGet || r.Method == http.MethodPost {
|
||||||
return []string{}, nil
|
return []string{}, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("nothing specified")
|
return nil, errors.New("nothing specified")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,368 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"local/dndex/storage/entity"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEntities(t *testing.T) {
|
||||||
|
rest, authit, clean := testREST(t)
|
||||||
|
defer clean()
|
||||||
|
|
||||||
|
t.Run("create+get1+delete+404", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id, ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname"
|
||||||
|
})
|
||||||
|
if id2 != id {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id, ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id, ``)
|
||||||
|
if w.Code != http.StatusNotFound {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("get1 404", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodGet, "/abc123", ``)
|
||||||
|
if w.Code != http.StatusNotFound {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+get0", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "attachments": {"abc": {}}, "connections": {"def": {"relationship": "ghi"}}}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname" && len(one.Attachments) == 1 && len(one.Connections) == 1 && one.Connections["def"].Relationship == "ghi"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/", ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
testEntitiesGetNResponse(t, w.Body, func(one shortEntity) bool {
|
||||||
|
return one.Name == "myname" && one.ID == id
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+replace+get1", func(t *testing.T) {
|
||||||
|
check := func(one entity.One) bool {
|
||||||
|
return one.Name == "myname"
|
||||||
|
}
|
||||||
|
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, check)
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodPut, "/"+id, `{"name":"newname"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id, ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "newname"
|
||||||
|
})
|
||||||
|
if id2 != id {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+get.title", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname" && one.Title == "mytitle"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodGet, "/"+id+"/title", ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
testEntitiesGetOneSubResponse(t, w.Body, func(v interface{}) bool {
|
||||||
|
return fmt.Sprint(v) == "mytitle"
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+update/replace", func(t *testing.T) {
|
||||||
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname" && one.Title == "mytitle"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id, `{"name": "newname"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "newname" && one.Title == ""
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+update/replace.name", func(t *testing.T) {
|
||||||
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname" && one.Title == "mytitle"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id+"/name", `"newname"`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "newname" && one.Title == "mytitle"
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+update/replace.connection.abc.relationship", func(t *testing.T) {
|
||||||
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"connections": {"abc": {"relationship": "def"}}}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Connections["abc"].Relationship == "def"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id+"/connections/abc/relationship", `"new"`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Connections["abc"].Relationship == "new"
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+update/replace.connection.abc", func(t *testing.T) {
|
||||||
|
for _, method := range []string{http.MethodPut, http.MethodPatch} {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"connections": {"abc": {"relationship": "def"}}}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Connections["abc"].Relationship == "def"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, method, "/"+id+"/connections/abc", `{"relationship": "new"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Connections["abc"].Relationship == "new"
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create+delete.name", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle"}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatal(w.Code)
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname" && one.Title == "mytitle"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id+"/name", ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "" && one.Title == "mytitle"
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create w connection.abc+delete.connections.abc", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"name":"myname", "title": "mytitle", "connections": {"abc": {"relationship": "good"}}}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
abc, ok := one.Connections["abc"]
|
||||||
|
return one.Name == "myname" && one.Title == "mytitle" && ok && abc.Relationship == "good"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id+"/connections/abc", ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return one.Name == "myname" && one.Title == "mytitle" && len(one.Connections) == 0
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("create w connection.abc.relationship+delete.connections.abc.relationship", func(t *testing.T) {
|
||||||
|
w := testEntitiesMethod(t, authit, rest, http.MethodPost, "/", `{"connections": {"abc": {"relationship": "good"}}}`)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
||||||
|
}
|
||||||
|
id := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
abc, ok := one.Connections["abc"]
|
||||||
|
return ok && abc.Relationship == "good"
|
||||||
|
})
|
||||||
|
|
||||||
|
w = testEntitiesMethod(t, authit, rest, http.MethodDelete, "/"+id+"/connections/abc/relationship", ``)
|
||||||
|
if w.Code != http.StatusOK {
|
||||||
|
t.Fatalf("%v: %s", w.Code, w.Body.Bytes())
|
||||||
|
}
|
||||||
|
id2 := testEntitiesGetOneResponse(t, w.Body, func(one entity.One) bool {
|
||||||
|
return len(one.Connections) == 1 && one.Connections["abc"].Relationship == ""
|
||||||
|
})
|
||||||
|
|
||||||
|
if id != id2 {
|
||||||
|
t.Fatal(id, id2)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEntitiesMethod(t *testing.T, authit func(*http.Request), rest *REST, method, p, body string) *httptest.ResponseRecorder {
|
||||||
|
r := httptest.NewRequest(method, p, strings.NewReader(body))
|
||||||
|
if !strings.HasPrefix(r.URL.Path, "/entities") {
|
||||||
|
r.URL.Path = path.Join("/entities", r.URL.Path)
|
||||||
|
}
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
authit(r)
|
||||||
|
rest.scoped(rest.shift(rest.entities))(w, r)
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEntitiesGetNResponse(t *testing.T, body io.Reader, check func(shortEntity) bool) {
|
||||||
|
var resp map[string][]shortEntity
|
||||||
|
if err := json.NewDecoder(body).Decode(&resp); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if len(resp) != 1 {
|
||||||
|
t.Fatal("excess found in db")
|
||||||
|
}
|
||||||
|
for k := range resp {
|
||||||
|
contents := resp[k]
|
||||||
|
if len(contents) < 1 {
|
||||||
|
t.Fatal(len(contents))
|
||||||
|
}
|
||||||
|
for i := range contents {
|
||||||
|
if check(contents[i]) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Fatal(contents)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEntitiesGetOneResponse(t *testing.T, body io.Reader, check func(entity.One) bool) string {
|
||||||
|
b, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var resp map[string]entity.One
|
||||||
|
if err := json.Unmarshal(b, &resp); err != nil {
|
||||||
|
t.Fatalf("%v: %s", err, b)
|
||||||
|
}
|
||||||
|
if len(resp) != 1 {
|
||||||
|
t.Fatal(len(resp))
|
||||||
|
}
|
||||||
|
for k := range resp {
|
||||||
|
one := resp[k]
|
||||||
|
if one.ID != k {
|
||||||
|
t.Fatal(k, one.ID)
|
||||||
|
}
|
||||||
|
if one.Modified == 0 {
|
||||||
|
t.Fatal(one.Modified)
|
||||||
|
}
|
||||||
|
if !check(one) {
|
||||||
|
t.Fatal(one)
|
||||||
|
}
|
||||||
|
return one.ID
|
||||||
|
}
|
||||||
|
panic("somehow no keys found")
|
||||||
|
}
|
||||||
|
|
||||||
|
func testEntitiesGetOneSubResponse(t *testing.T, body io.Reader, check func(interface{}) bool) {
|
||||||
|
b, err := ioutil.ReadAll(body)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
var resp map[string]interface{}
|
||||||
|
if err := json.Unmarshal(b, &resp); err != nil {
|
||||||
|
t.Fatalf("%v: %s", err, b)
|
||||||
|
}
|
||||||
|
if len(resp) != 1 {
|
||||||
|
t.Fatal(len(resp))
|
||||||
|
}
|
||||||
|
for k := range resp {
|
||||||
|
one := resp[k]
|
||||||
|
if !check(one) {
|
||||||
|
t.Fatal(one)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
panic("somehow no keys found")
|
||||||
|
}
|
||||||
|
|
@ -310,6 +310,14 @@ func applySet(doc, operator bson.M) (bson.M, error) {
|
||||||
if k == entity.ID {
|
if k == entity.ID {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if k == "." {
|
||||||
|
m, ok := v.(bson.M)
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("cannot assign non-map to doc")
|
||||||
|
}
|
||||||
|
doc = m
|
||||||
|
return doc, nil
|
||||||
|
}
|
||||||
nesting := strings.Split(k, ".")
|
nesting := strings.Split(k, ".")
|
||||||
if len(nesting) > 1 {
|
if len(nesting) > 1 {
|
||||||
mInterface, ok := doc[nesting[0]]
|
mInterface, ok := doc[nesting[0]]
|
||||||
|
|
|
||||||
|
|
@ -74,10 +74,8 @@ func (g Graph) Insert(ctx context.Context, namespace string, one entity.One) err
|
||||||
if one.ID == "" {
|
if one.ID == "" {
|
||||||
return errors.New("cannot create document without id")
|
return errors.New("cannot create document without id")
|
||||||
}
|
}
|
||||||
if ones, err := g.ListCaseInsensitive(ctx, namespace, one.ID); err != nil {
|
if one, err := g.Get(ctx, namespace, one.ID); err == nil {
|
||||||
return err
|
return fmt.Errorf("collision on primary key when case insensitive: cannot create %q because %+v exists", one.ID, one)
|
||||||
} else if len(ones) > 0 {
|
|
||||||
return fmt.Errorf("collision on primary key when case insensitive: cannot create %q because %+v exists", one.ID, ones)
|
|
||||||
}
|
}
|
||||||
return g.driver.Insert(ctx, namespace, one)
|
return g.driver.Insert(ctx, namespace, one)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue