Example #1
0
func Post(w http.ResponseWriter, r *http.Request) {
	ctx := getContext(r)
	var err error
	var rev string

	if ctx.jsonBody == nil {
		res := responses.BadRequest("You must send a JSON body for this request.")
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	if ctx.lastKey == "_bulk_get" {
		BulkGet(w, r)
		return
	} else if ctx.lastKey == "_bulk_docs" {
		BulkDocs(w, r)
		return
	} else if ctx.lastKey == "_revs_diff" {
		RevsDiff(w, r)
		return
	}

	if ctx.lastKey[0] == '_' {
		res := responses.BadRequest("you can't post to special keys.")
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	// POST is supposed to generate a new doc, with a new random _id:
	id := db.Random(7)
	path := ctx.path + "/" + id

	if ctx.jsonBody != nil {
		// if it is JSON we must save it as its structure demands
		rev, err = db.SaveTreeAt(path, ctx.jsonBody)
	} else {
		// otherwise it's an error
		res := responses.BadRequest("you need to send a JSON body for this request.")
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	if err != nil {
		log.Error("couldn't save value: ", err)
		res := responses.UnknownError(err.Error())
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	w.WriteHeader(201)
	w.Header().Add("Content-Type", "application/json")
	json.NewEncoder(w).Encode(responses.Success{true, id, rev})
}
Example #2
0
// this method only exists for compatibility with PouchDB and should not be used elsewhere.
func BulkDocs(w http.ResponseWriter, r *http.Request) {
	ctx := getContext(r)
	var idocs interface{}
	var iid interface{}
	var irev interface{}
	var id string
	var rev string
	var ok bool

	if idocs, ok = ctx.jsonBody["docs"]; !ok {
		res := responses.BadRequest("You're supposed to send an array of docs to input on the database, and you didn't.")
		w.WriteHeader(res.Code)
		json.NewEncoder(w).Encode(res)
		return
	}

	/* options */
	new_edits := true
	if inew_edits, ok := ctx.jsonBody["new_edits"]; ok {
		new_edits = inew_edits.(bool)
	}

	path := db.CleanPath(ctx.path)
	docs := idocs.([]interface{})
	res := make([]responses.BulkDocsResult, len(docs))

	var err error
	if new_edits { /* procedure for normal document saving */
		for i, idoc := range docs {

			var newrev string
			localDoc := false
			doc := idoc.(map[string]interface{})
			if iid, ok = doc["_id"]; ok {
				id = iid.(string)
				if strings.HasPrefix(id, "_local/") {
					localDoc = true
				}
				if irev, ok = doc["_rev"]; ok {
					rev = irev.(string)
				} else {
					rev = ""
				}
			} else {
				id = db.Random(5)
			}

			if !localDoc {
				// procedure for normal documents

				// check rev matching:
				if iid != nil /* when iid is nil that means the doc had no _id, so we don't have to check. */ {
					currentRev := db.GetRev(path + "/" + db.EscapeKey(id))
					if string(currentRev) != rev && !bytes.HasPrefix(currentRev, []byte{'0', '-'}) {
						// rev is not matching, don't input this document
						e := responses.ConflictError()
						res[i] = responses.BulkDocsResult{
							Id:     id,
							Error:  e.Error,
							Reason: e.Reason,
						}
						continue
					}
				}

				// proceed to write the document.
				newrev, err = db.ReplaceTreeAt(path+"/"+db.EscapeKey(id), doc, false)
				if err != nil {
					e := responses.UnknownError()
					res[i] = responses.BulkDocsResult{
						Id:     id,
						Error:  e.Error,
						Reason: e.Reason,
					}
					continue
				}

			} else {
				// procedure for local documents

				// check rev matching:
				currentRev := db.GetLocalDocRev(path + "/" + id)
				if currentRev != "0-0" && currentRev != rev {
					// rev is not matching, don't input this document
					e := responses.ConflictError()
					res[i] = responses.BulkDocsResult{
						Id:     id,
						Error:  e.Error,
						Reason: e.Reason,
					}
					continue
				}

				// proceed to write the document.
				newrev, err = db.SaveLocalDocAt(path+"/"+id, doc)
				if err != nil {
					e := responses.UnknownError()
					res[i] = responses.BulkDocsResult{
						Id:     id,
						Error:  e.Error,
						Reason: e.Reason,
					}
					continue
				}
			}

			res[i] = responses.BulkDocsResult{
				Id:  id,
				Ok:  true,
				Rev: newrev,
			}
		}
	} else { /* procedure for replication-type _bulk_docs (new_edits=false)*/
		for i, idoc := range docs {
			id = ""
			rev = ""
			doc := idoc.(map[string]interface{})
			if iid, ok = doc["_id"]; ok {
				id = iid.(string)
				if irev, ok = doc["_rev"]; ok {
					rev = irev.(string)
				}
			}
			if id == "" || rev == "" {
				e := responses.UnknownError()
				res[i] = responses.BulkDocsResult{
					Id:     id,
					Error:  e.Error,
					Reason: e.Reason,
				}
				continue
			}

			// proceed to write
			currentRev := db.GetRev(path + "/" + db.EscapeKey(id))
			if rev < string(currentRev) {
				// will write only the rev if it is not the winning rev
				db.AcknowledgeRevFor(path+"/"+db.EscapeKey(id), rev)

			} else {
				// otherwise will write the whole doc normally (replacing the current)
				rev, err = db.ReplaceTreeAt(path+"/"+db.EscapeKey(id), doc, true)
			}

			// handle write error
			if err != nil {
				e := responses.UnknownError()
				res[i] = responses.BulkDocsResult{
					Id:     id,
					Error:  e.Error,
					Reason: e.Reason,
				}
				continue
			}

			res[i] = responses.BulkDocsResult{
				Id:  id,
				Ok:  true,
				Rev: rev,
			}
		}
	}

	w.WriteHeader(201)
	json.NewEncoder(w).Encode(res)
}