コード例 #1
0
ファイル: graphql.go プロジェクト: fiatjaf/summadb
func godeep(field *ast.Field, path string, base *cmap.ConcurrentMap) {
	alias := field.Name.Value
	if field.Alias != nil {
		alias = field.Alias.Value
	}

	if field.SelectionSet == nil {
		// end of line
		var val []byte
		if field.Name.Value == "_val" {
			val, _ = db.GetValueAt(path)
		} else {
			val, _ = db.GetValueAt(path + "/" + field.Name.Value)
		}
		base.Set(alias, db.FromLevel(val))
	} else {
		// will continue with the following selections
		next := cmap.New()
		base.Set(alias, next)
		godeepAsyncMultiple(
			field.SelectionSet.Selections,
			path+"/"+field.Name.Value,
			&next,
		)
	}
}
コード例 #2
0
ファイル: specialhandlers.go プロジェクト: fiatjaf/summadb
// this method only exists for compatibility with PouchDB and should not be used elsewhere.
func RevsDiff(w http.ResponseWriter, r *http.Request) {
	ctx := getContext(r)

	path := db.CleanPath(ctx.path)

	res := make(map[string]responses.RevsDiffResult)
	for id, irevs := range ctx.jsonBody {
		missing := make([]string, 0)

		currentRevb, err := db.GetValueAt(path + "/" + id + "/_rev")
		if err != nil {
			/* no _rev for this id, means it has never been inserted in this database.
			   let's say we miss all the revs. */
			for _, irev := range irevs.([]interface{}) {
				rev := irev.(string)
				missing = append(missing, rev)
			}
		} else {
			/* otherwise we will say we have the current rev and none of the others,
			   because that's the truth. */
			// TODO maybe here we should say that we have these old revs
			// --  either we actually have them, but they are deleted, or
			//     we don't, but they are unnecessary anyway.
			currentRev := string(currentRevb)
			for _, irev := range irevs.([]interface{}) {
				rev := irev.(string)
				if rev != currentRev {
					missing = append(missing, rev)
				}
			}
		}

		res[id] = responses.RevsDiffResult{Missing: missing}
	}

	w.WriteHeader(200)
	json.NewEncoder(w).Encode(res)
}
コード例 #3
0
ファイル: basics_test.go プロジェクト: fiatjaf/summadb
func TestBasics(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("basics test", func() {

		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should save a tree", func() {
			db.SaveTreeAt("/fruits/banana", map[string]interface{}{
				"colour":   "yellow",
				"hardness": "low",
				"_val":     "a fruit.",
			})
			Expect(db.GetValueAt("/fruits/banana")).To(BeEquivalentTo(`"a fruit."`))
			Expect(db.GetValueAt("/fruits/banana/colour")).To(BeEquivalentTo(`"yellow"`))
			Expect(db.GetValueAt("/fruits/banana/hardness")).To(BeEquivalentTo(`"low"`))
			_, err := db.GetValueAt("/fruits")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("/fruits")).To(Equal(map[string]interface{}{
				"banana": map[string]interface{}{
					"colour":   value("yellow"),
					"hardness": value("low"),
					"_val":     "a fruit.",
				},
			}))
		})

		g.It("should modify a subvalue of the tree", func() {
			db.SaveValueAt("/fruits/banana/colour", []byte(`"black-and-yellow"`))
			Expect(db.GetValueAt("/fruits/banana/colour")).To(BeEquivalentTo(`"black-and-yellow"`))
			Expect(db.GetValueAt("/fruits/banana/hardness")).To(BeEquivalentTo(`"low"`))
		})

		g.It("should add a value deeply nested in a tree that doesn't exists", func() {
			db.SaveValueAt("/fruits/mellon/season", []byte(`"spring"`))
			Expect(db.GetValueAt("/fruits/mellon/season")).To(BeEquivalentTo(`"spring"`))
			Expect(db.GetTreeAt("/fruits")).To(Equal(map[string]interface{}{
				"banana": map[string]interface{}{
					"colour":   value("black-and-yellow"),
					"hardness": value("low"),
					"_val":     "a fruit.",
				},
				"mellon": map[string]interface{}{
					"season": value("spring"),
				},
			}))
		})

		g.It("should add a tree deeply nested like the previous", func() {
			db.SaveTreeAt("/fruits/orange", map[string]interface{}{
				"colour":   "orange",
				"hardness": "medium",
				"_val":     "name == colour",
			})
			Expect(db.GetValueAt("/fruits/orange/colour")).To(BeEquivalentTo(`"orange"`))
			Expect(db.GetValueAt("/fruits/orange")).To(BeEquivalentTo(`"name == colour"`))
			Expect(db.GetTreeAt("/fruits/orange")).To(Equal(map[string]interface{}{
				"_val":     "name == colour",
				"colour":   value("orange"),
				"hardness": value("medium"),
			}))
		})

		g.It("should delete a key", func() {
			db.DeleteAt("/fruits/banana/colour")
			Expect(db.GetValueAt("/fruits/orange/colour")).To(BeEquivalentTo(`"orange"`))
			_, err := db.GetValueAt("/fruits/banana/colour")
			Expect(db.GetValueAt("/fruits/banana/colour/_deleted")).To(BeEquivalentTo(""))
			Expect(err).To(HaveOccurred())
		})

		g.It("should delete a value when setting it to null with a tree", func() {
			db.SaveTreeAt("/fruits/mellon", map[string]interface{}{
				"colour": "orange",
				"season": nil,
			})
			Expect(db.GetValueAt("/fruits/mellon/colour")).To(BeEquivalentTo(`"orange"`))
			_, err := db.GetValueAt("/fruits/mellon/season")
			Expect(err).To(HaveOccurred())

			db.SaveTreeAt("/fruits", map[string]interface{}{
				"mellon": nil,
			})
			_, err = db.GetValueAt("/fruits/mellon/colour")
			Expect(err).To(HaveOccurred())
			_, err = db.GetValueAt("/fruits/mellon")
			Expect(err).To(HaveOccurred())
		})

		g.It("should delete a tree", func() {
			db.DeleteAt("/fruits/banana")
			Expect(db.GetValueAt("/fruits/orange/colour")).To(BeEquivalentTo(`"orange"`))
			_, err := db.GetValueAt("/fruits/banana/hardness")
			Expect(err).To(HaveOccurred())

			rev, err := db.DeleteAt("/fruits")
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("9-"))
			_, err = db.GetValueAt("/fruits")
			Expect(err).To(HaveOccurred())
			Expect(db.GetValueAt("/fruits/orange/_deleted")).To(BeEquivalentTo(""))
			_, err = db.GetValueAt("/fruits/orange/colour")
			Expect(err).To(HaveOccurred())
			_, err = db.GetValueAt("/fruits/banana/hardness")
			Expect(err).To(HaveOccurred())
		})

		g.It("should error when fetching an untouched tree path", func() {
			_, err := db.GetTreeAt("/nowhere")
			Expect(err).To(HaveOccurred())
		})

		g.It("should return when fetching a deleted tree path", func() {
			tree, err := db.GetTreeAt("/fruits/banana")
			Expect(err).ToNot(HaveOccurred())
			empty := make(map[string]interface{})
			Expect(tree).To(BeEquivalentTo(empty))
		})
	})
}
コード例 #4
0
func TestCouchDBSpecialEndpoints(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("couchdb db special endpoints", func() {
		g.BeforeEach(func() {
			rec = httptest.NewRecorder()
			server = handle.BuildHandler()
		})

		g.Before(func() {
			db.Erase()
			db.Start()
			populateDB()
		})

		g.After(func() {
			db.End()
		})

		var rev string
		var oldrev string
		var id string

		g.It("_all_docs for a sub db", func() {
			r, _ = http.NewRequest("GET", "/vehicles/_all_docs", nil)
			server.ServeHTTP(rec, r)

			var res responses.AllDocs
			json.Unmarshal(rec.Body.Bytes(), &res)
			Expect(res.Rows).To(HaveLen(3))
			Expect(res.Rows[2].Id).To(Equal(res.Rows[2].Key))
			rev, _ := res.Rows[2].Value.(map[string]interface{})["rev"]
			Expect(rev).To(HavePrefix("1-"))

			keys := []string{res.Rows[0].Id, res.Rows[1].Key, res.Rows[2].Id}
			Expect(keys).To(ConsistOf("airplane", "boat", "car"))
		})

		g.It("_all_docs with selected keys", func() {
			r, _ = http.NewRequest("GET", "/vehicles/_all_docs?keys=%5B%22airplane%22,%22boat%22%5D", nil)
			server.ServeHTTP(rec, r)

			var res responses.AllDocs
			json.Unmarshal(rec.Body.Bytes(), &res)
			Expect(res.Rows).To(HaveLen(2))

			keys := []string{res.Rows[0].Id, res.Rows[1].Key}
			Expect(keys).To(ConsistOf("airplane", "boat"))
		})

		g.It("all_docs with include_docs -- for another sub db", func() {
			r, _ = http.NewRequest("GET", "/vehicles/airplane/_all_docs?include_docs=true", nil)
			server.ServeHTTP(rec, r)

			var res responses.AllDocs
			json.Unmarshal(rec.Body.Bytes(), &res)
			Expect(res.Rows).To(HaveLen(3))

			docid, _ := res.Rows[1].Doc["_id"]
			Expect(res.Rows[1].Key).To(Equal(docid))

			rev, _ := res.Rows[1].Value.(map[string]interface{})["rev"]
			docrev, _ := res.Rows[1].Doc["_rev"]
			Expect(rev).To(Equal(docrev))

			keys := []string{res.Rows[0].Id, res.Rows[1].Key, res.Rows[2].Id}
			sort.Strings(keys)
			Expect(keys).To(Equal([]string{"air", "land", "water"}))

			docs := map[string]interface{}{
				res.Rows[0].Key: res.Rows[0].Doc,
				res.Rows[1].Key: res.Rows[1].Doc,
				res.Rows[2].Key: res.Rows[2].Doc,
			}
			Expect(docs).To(HaveKey("air"))
			Expect(res.Rows[0].Doc).To(HaveKey("_rev"))
			Expect(res.Rows[0].Doc).To(HaveKeyWithValue("_id", res.Rows[0].Id))
		})

		g.It("_bulk_get", func() {
			r, _ = http.NewRequest("POST", "/vehicles/_bulk_get", bytes.NewReader([]byte(`{
                "docs": [
                    {"id": "nonexisting-doc"},
                    {"id": "car"},
                    {"_id": "airplane"}
                ]
            }`)))
			server.ServeHTTP(rec, r)

			var res responses.BulkGet
			json.Unmarshal(rec.Body.Bytes(), &res)
			Expect(res.Results[0].Docs[0].Ok).To(BeNil())
			Expect(res.Results[0].Docs[0].Error).ToNot(BeNil())
			Expect(res.Results[1].Docs[0].Ok).ToNot(BeNil())
			Expect(res.Results[1].Docs[0].Error).To(BeNil())
			doc := *res.Results[1].Docs[0].Ok
			id, _ := doc["_id"]
			irev, _ := doc["_rev"]
			rev = irev.(string)
			water, _ := doc["water"]
			Expect(id.(string)).To(Equal("car"))
			Expect(res.Results[1].Id).To(Equal(id))
			Expect(water).To(BeEquivalentTo(value(false)))
			Expect(res.Results[2].Docs[0].Ok).To(BeNil())
			Expect(res.Results[0].Docs[0].Error).ToNot(BeNil())
		})

		g.It("_bulk_docs", func() {
			r, _ = http.NewRequest("POST", "/vehicles/_bulk_docs", bytes.NewReader([]byte(`{
                "docs": [
                    {"everywhere": true},
                    {"_id": "car", "_rev": "`+rev+`", "space": false, "land": true},
                    {"_id": "airplane", "nowhere": false},
                    {"_id": "_local/.abchtru", "replication+data": "k"},
                    {"_id": "empty-doc"},
                    {"_id": "doc-with-a-rev-already-set", "_rev": "4-sa98hsa3i4", "val": 33}
                ]
            }`)))
			server.ServeHTTP(rec, r)

			Expect(rec.Code).To(Equal(201))
			var res []responses.BulkDocsResult
			json.Unmarshal(rec.Body.Bytes(), &res)

			Expect(res).To(HaveLen(6))
			Expect(res[0].Error).To(Equal(""))
			Expect(res[0].Ok).To(Equal(true))
			Expect(res[0].Rev).To(HavePrefix("1-"))
			id = res[0].Id
			Expect(res[1].Id).To(Equal("car"))
			prevn, _ := strconv.Atoi(strings.Split(rev, "-")[0])
			Expect(res[1].Rev).To(HavePrefix(fmt.Sprintf("%d-", prevn+1)))
			oldrev = rev
			rev = res[1].Rev
			cfe := responses.ConflictError()
			Expect(res[2].Error).To(Equal(cfe.Error))
			Expect(res[3].Id).To(Equal("_local/.abchtru"))
			Expect(res[3].Ok).To(Equal(true))
			Expect(res[4].Ok).To(Equal(true))
			Expect(res[4].Rev).To(HavePrefix("1-"))
			Expect(res[5].Ok).To(Equal(true))
			Expect(res[5].Rev).To(HavePrefix("5-"))
		})

		g.It("_bulk_docs with new_edits=false", func() {
			r, _ = http.NewRequest("POST", "/animals/_bulk_docs", bytes.NewReader([]byte(`{
                "docs": [
                    {"_id": "0", "_rev": "34-83fsop4", "name": "albatroz"},
                    {"_id": "1", "_rev": "0-a0a0a0a0", "name": "puppy"},
                    {"_id": "2"}
                ],
                "new_edits": false
            }`)))
			server.ServeHTTP(rec, r)

			Expect(rec.Code).To(Equal(201))
			var res []responses.BulkDocsResult
			json.Unmarshal(rec.Body.Bytes(), &res)

			Expect(res).To(HaveLen(3))
			Expect(res[0].Ok).To(Equal(true))
			Expect(res[1].Ok).To(Equal(true))
			Expect(res[2].Ok).To(Equal(false))

			Expect(db.GetRev("/animals/0")).To(BeEquivalentTo("34-83fsop4"))
			Expect(db.GetRev("/animals/1")).ToNot(BeEquivalentTo("0-a0a0a0a0"))
			Expect(db.GetValueAt("/animals/0/name")).To(BeEquivalentTo(`"albatroz"`))
			Expect(db.GetValueAt("/animals/1/name")).To(BeEquivalentTo(`"dog"`))
		})

		g.It("should have the correct docs saved", func() {
			Expect(db.GetValueAt("/vehicles/" + id + "/everywhere")).To(BeEquivalentTo("true"))
			Expect(db.GetLocalDocJsonAt("/vehicles/_local/.abchtru")).To(MatchJSON(`{
                "_id": "_local/.abchtru",
                "_rev": "0-1",
                "replication+data": "k"
            }`))
		})

		g.It("shouldn't show _local docs on _all_docs", func() {
			r, _ = http.NewRequest("GET", "/vehicles/_all_docs", nil)
			server.ServeHTTP(rec, r)
			var res responses.AllDocs
			json.Unmarshal(rec.Body.Bytes(), &res)
			Expect(res.Rows).To(HaveLen(5))
		})

		g.It("_revs_diff", func() {
			r, _ = http.NewRequest("POST", "/vehicles/_revs_diff", bytes.NewReader([]byte(`{
                "everywhere": ["2-invalidrev"],
                "car": ["`+oldrev+`", "`+rev+`", "1-invalidrev"],
                "airplane": ["1-nonexisting"]
            }`)))
			server.ServeHTTP(rec, r)

			Expect(rec.Code).To(Equal(200))
			var res map[string]responses.RevsDiffResult
			json.Unmarshal(rec.Body.Bytes(), &res)

			everywhere, _ := res["everywhere"]
			car, _ := res["car"]
			airplane, _ := res["airplane"]
			Expect(everywhere.Missing).To(Equal([]string{"2-invalidrev"}))
			Expect(car.Missing).To(Equal([]string{oldrev, "1-invalidrev"}))
			Expect(airplane.Missing).To(Equal([]string{"1-nonexisting"}))
		})
	})
}
コード例 #5
0
ファイル: revs_test.go プロジェクト: fiatjaf/summadb
func TestRevs(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("_rev", func() {

		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should generate _rev for a single key", func() {
			savedrev, _ := db.SaveValueAt("/name", []byte(`"database of vehicles"`))
			gottenrev, _ := db.GetValueAt("/name/_rev")
			Expect(savedrev).To(BeEquivalentTo(gottenrev))
			Expect(gottenrev).To(HavePrefix("1-"))
		})

		g.It("should generate _rev for parent keys", func() {
			db.SaveValueAt("/vehicles/car/land", []byte("true"))
			db.SaveValueAt("/vehicles/carriage/land", []byte("true"))
			db.SaveValueAt("/vehicles/carriage/air", []byte("false"))
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump _rev for single keys", func() {
			db.SaveValueAt("/name", []byte(`"just a database of vehicles"`))
			Expect(db.GetValueAt("/name/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump _rev for parent keys", func() {
			db.SaveValueAt("/vehicles/car/water", []byte("false"))
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))

			db.SaveValueAt("/vehicles/boat/water", []byte("true"))
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("5-"))
		})

		g.It("on delete, should bump _rev for parents and sons", func() {
			db.DeleteAt("/vehicles/car")
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("6-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump rev of all parents of affected keys", func() {
			db.SaveTreeAt("/vehicles/boat", map[string]interface{}{
				"water": true,
				"land":  false,
				"air":   false,
			})
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/air/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("7-"))
		})

		g.It("doing it again to make sure", func() {
			db.SaveTreeAt("/vehicles", map[string]interface{}{
				"car": map[string]interface{}{
					"water": true,
				},
				"boat": map[string]interface{}{
					"air": true,
				},
			})
			Expect(db.GetValueAt("/vehicles/car/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/car/water/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/boat/air/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("8-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("2-"))
		})

		g.It("should bump the revs correctly when a tree operation involves deleting", func() {
			db.SaveTreeAt("/vehicles", map[string]interface{}{
				"carriage": map[string]interface{}{
					"space": false,
					"land":  nil,
				},
				"boat": nil,
			})
			Expect(db.GetValueAt("/vehicles/car/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/boat/water/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/boat/air/_rev")).To(HavePrefix("3-"))
			Expect(db.GetValueAt("/vehicles/boat/_rev")).To(HavePrefix("4-"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("9-"))
			Expect(db.GetValueAt("/vehicles/carriage/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/carriage/_rev")).To(HavePrefix("3-"))
		})

		g.It("should bump revs of intermediate paths when modifying a deep field", func() {
			db.SaveValueAt("/vehicles/train/land/rail", []byte("true"))
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("10-"))
			Expect(db.GetValueAt("/vehicles/train/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/train/land/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/train/land/rail/_rev")).To(HavePrefix("1-"))

			db.DeleteAt("/vehicles/train")
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("11-"))
			Expect(db.GetValueAt("/vehicles/train/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/train/land/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/train/land/rail/_rev")).To(HavePrefix("2-"))

			db.SaveTreeAt("", map[string]interface{}{
				"vehicles": map[string]interface{}{
					"skate": map[string]interface{}{
						"air": map[string]interface{}{
							"carried": map[string]interface{}{
								"_val": true,
							},
						},
					},
				},
			})
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("12-"))
			Expect(db.GetValueAt("/vehicles/skate/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/skate/air/_rev")).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/vehicles/skate/air/carried/_rev")).To(HavePrefix("1-"))

			db.SaveTreeAt("", map[string]interface{}{
				"vehicles": map[string]interface{}{
					"skate": map[string]interface{}{
						"air": map[string]interface{}{
							"carried": nil,
						},
					},
				},
			})
			Expect(db.GetValueAt("/vehicles/_rev")).To(HavePrefix("13-"))
			Expect(db.GetValueAt("/vehicles/skate/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/skate/air/_rev")).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/vehicles/skate/air/carried/_rev")).To(HavePrefix("2-"))
		})

		g.It("should return rev", func() {
			sk, err := db.GetSpecialKeysAt("/vehicles/skate")
			Expect(err).ToNot(HaveOccurred())
			Expect(sk.Rev).To(HavePrefix("2-"))
		})
	})
}
コード例 #6
0
func TestCouchDBDocsSpecial(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("couchdb documents special endpoints", func() {
		g.BeforeEach(func() {
			rec = httptest.NewRecorder()
			server = handle.BuildHandler()
		})

		g.Before(func() {
			db.Erase()
			db.Start()
			populateDB()
		})

		g.After(func() {
			db.End()
		})

		var rev string

		g.It("should change some values to generate revs", func() {
			brev, _ := db.GetValueAt("/vehicles/boat/air/_rev")
			r, _ = http.NewRequest("PUT", "/vehicles/boat/air/_val", bytes.NewReader([]byte("true")))
			r.Header.Add("If-Match", string(brev))
			server.ServeHTTP(rec, r)
			Expect(rec.Code).To(Equal(201))

			var res responses.Success
			json.Unmarshal(rec.Body.Bytes(), &res)
			rev = res.Rev
		})

		g.It("once more:", func() {
			r, _ = http.NewRequest("PATCH", "/vehicles/boat/air", bytes.NewReader([]byte(`{
                "_rev": "`+rev+`",
                "really?": false
            }`)))
			server.ServeHTTP(rec, r)
			Expect(rec.Code).To(Equal(200))
		})

		g.It("should fetch some key with the _revisions special field", func() {
			r, _ = http.NewRequest("GET", "/vehicles?revs=true", nil)
			server.ServeHTTP(rec, r)

			var res map[string]interface{}
			json.Unmarshal(rec.Body.Bytes(), &res)

			irevisions, ok := res["_revisions"]
			Expect(ok).To(Equal(true))
			revisions := irevisions.(map[string]interface{})
			start, _ := revisions["start"]
			ids, _ := revisions["ids"]
			Expect(start).To(BeEquivalentTo(1))
			Expect(ids).To(HaveLen(3))
		})

		g.It("should fetch some key with the _revs_info special field", func() {
			r, _ = http.NewRequest("GET", "/vehicles/boat?revs_info=true", nil)
			server.ServeHTTP(rec, r)

			var res map[string]interface{}
			json.Unmarshal(rec.Body.Bytes(), &res)

			irevsinfo, ok := res["_revs_info"]
			Expect(ok).To(Equal(true))
			revsinfo := irevsinfo.([]interface{})
			Expect(revsinfo).To(HaveLen(3))

			first := revsinfo[0].(map[string]interface{})
			second := revsinfo[1].(map[string]interface{})
			status, _ := first["status"]
			Expect(status).To(BeEquivalentTo("available"))
			status, _ = second["status"]
			Expect(status).To(BeEquivalentTo("missing"))
		})
	})
}
コード例 #7
0
ファイル: handlers.go プロジェクト: fiatjaf/summadb
func Get(w http.ResponseWriter, r *http.Request) {
	ctx := getContext(r)

	/* here we handle special endpoints that, in CouchDB, refer to a database,
	   but here are treated as documents (or better, subtrees) methods */
	if ctx.wantsDatabaseInfo {
		DatabaseInfo(w, r)
		return
	} else if ctx.lastKey == "_changes" {
		Changes(w, r)
		return
	} else if ctx.lastKey == "_all_docs" {
		AllDocs(w, r)
		return
	} else if ctx.lastKey == "_security" {
		ReadSecurity(w, r)
		return
	} else if ctx.lastKey == "_missing_revs" {
		return
	}

	var response []byte
	var err error

	if !ctx.exists {
		res := responses.NotFound()
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	if ctx.localDoc {
		jsondoc, err := db.GetLocalDocJsonAt(ctx.path)
		if err != nil {
			// ctx.exists doesn't work for _local docs
			res := responses.NotFound()
			w.WriteHeader(res.Code)
			json.NewEncoder(w).Encode(res)
			return
		}

		w.WriteHeader(200)
		w.Header().Add("Content-Type", "application/json")
		w.Write(jsondoc)
		return
	}

	if ctx.wantsTree {
		var tree map[string]interface{}
		tree, err = db.GetTreeAt(ctx.path)
		if err == nil {
			tree["_id"] = ctx.lastKey
			tree["_rev"] = ctx.currentRev

			if flag(r, "revs") {
				var revs []string
				revs, err = db.RevsAt(ctx.path)
				if err == nil {
					var start int
					start, err = strconv.Atoi(strings.Split(revs[0], "-")[0])
					revids := make([]string, len(revs))
					for i, rev := range revs {
						revids[i] = strings.Split(rev, "-")[1]
					}
					tree["_revisions"] = responses.Revisions{
						Start: start,
						Ids:   revids,
					}
				}
			}

			if flag(r, "revs_info") {
				var revs []string
				revs, err = db.RevsAt(ctx.path)
				if err == nil {
					revsInfo := make([]responses.RevInfo, len(revs))
					i := 0
					for r := len(revs) - 1; r >= 0; r-- {
						revsInfo[i] = responses.RevInfo{
							Rev:    revs[r],
							Status: "missing",
						}
						i++
					}
					revsInfo[0].Status = "available"
					tree["_revs_info"] = revsInfo
				}
			}

			response, err = json.Marshal(tree)
		}
	} else {
		if ctx.lastKey == "_rev" {
			response = []byte(ctx.currentRev)
		} else {
			response, err = db.GetValueAt(ctx.path)
			if err != nil {
				res := responses.NotFound()
				w.WriteHeader(res.Code)
				json.NewEncoder(w).Encode(res)
				return
			}
		}
	}

	if err != nil {
		res := responses.UnknownError(err.Error())
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	w.WriteHeader(200)
	w.Header().Add("Content-Type", "application/json")
	w.Write(response)
}
コード例 #8
0
ファイル: idempotent_test.go プロジェクト: fiatjaf/summadb
func TestIdempotent(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("idempotent put", func() {
		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should put a tree", func() {
			Expect(db.ReplaceTreeAt("/fruits/banana", map[string]interface{}{
				"colour":   "yellow",
				"hardness": "low",
				"_val":     "a fruit.",
			}, false)).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/fruits/banana")).To(BeEquivalentTo(`"a fruit."`))
			Expect(db.GetValueAt("/fruits/banana/colour")).To(BeEquivalentTo(`"yellow"`))
		})

		g.It("should replace it with a totally different object with arrays", func() {
			rev, err := db.ReplaceTreeAt("", map[string]interface{}{
				"what":    "numbers",
				"numbers": []interface{}{"zero", "one", "two", "three"},
			}, false)
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/numbers/3")).To(BeEquivalentTo(`"three"`))
			_, err = db.GetValueAt("/numbers")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("")).To(Equal(map[string]interface{}{
				"what": value("numbers"),
				"numbers": map[string]interface{}{
					"0": value("zero"),
					"1": value("one"),
					"2": value("two"),
					"3": value("three"),
				},
			}))
			_, err = db.GetValueAt("/fruits")
			Expect(err).To(HaveOccurred())
		})

		g.It("should replace it again with a totally different object", func() {
			Expect(db.ReplaceTreeAt("/fruits/orange", map[string]interface{}{
				"colour": "orange",
			}, false)).To(HavePrefix("1-"))
			Expect(db.GetTreeAt("")).To(Equal(map[string]interface{}{
				"what": value("numbers"),
				"numbers": map[string]interface{}{
					"0": value("zero"),
					"1": value("one"),
					"2": value("two"),
					"3": value("three"),
				},
				"fruits": map[string]interface{}{
					"orange": map[string]interface{}{
						"colour": value("orange"),
					},
				},
			}))
		})

		g.It("should put an empty object", func() {
			rev, err := db.ReplaceTreeAt("/fruits/watermellon", map[string]interface{}{}, false)
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("1-"))
		})
	})
}
コード例 #9
0
ファイル: arrays_test.go プロジェクト: fiatjaf/summadb
func TestArrays(t *testing.T) {
	g := Goblin(t)
	RegisterFailHandler(func(m string, _ ...int) { g.Fail(m) })

	g.Describe("array values", func() {
		g.Before(func() {
			db.Erase()
			db.Start()
		})

		g.After(func() {
			db.End()
		})

		g.It("should save a tree with a simple array", func() {
			rev, err := db.SaveTreeAt("", map[string]interface{}{
				"numbers": []interface{}{"zero", "one", "two", "three"},
			})
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("1-"))
			Expect(db.GetValueAt("/numbers/0")).To(BeEquivalentTo(`"zero"`))
			Expect(db.GetValueAt("/numbers/3")).To(BeEquivalentTo(`"three"`))
			_, err = db.GetValueAt("/numbers")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("/numbers")).To(Equal(map[string]interface{}{
				"0": value("zero"),
				"1": value("one"),
				"2": value("two"),
				"3": value("three"),
			}))
		})

		g.It("should save a tree with a complex array", func() {
			rev, err := db.SaveTreeAt("", map[string]interface{}{
				"letters": []interface{}{
					map[string]interface{}{
						"name":       "á",
						"variations": []interface{}{"a", "A"},
					},
					map[string]interface{}{
						"name":       "bê",
						"variations": []interface{}{"b", "B"},
					},
				},
			})
			Expect(err).ToNot(HaveOccurred())
			Expect(rev).To(HavePrefix("2-"))
			Expect(db.GetValueAt("/letters/0/name")).To(BeEquivalentTo(`"á"`))
			Expect(db.GetValueAt("/letters/1/variations/1")).To(BeEquivalentTo(`"B"`))
			_, err = db.GetValueAt("/letters/0/variations")
			Expect(err).To(HaveOccurred())
			Expect(db.GetTreeAt("/letters")).To(Equal(map[string]interface{}{
				"0": map[string]interface{}{
					"name": value("á"),
					"variations": map[string]interface{}{
						"0": value("a"),
						"1": value("A"),
					},
				},
				"1": map[string]interface{}{
					"name": value("bê"),
					"variations": map[string]interface{}{
						"0": value("b"),
						"1": value("B"),
					},
				},
			}))
		})
	})
}