1
0
Fork 0

Merge branch 'spdvpk' of https://github.com/arangodb/arangodb into spdvpk

This commit is contained in:
Jan Steemann 2016-03-01 11:14:55 +01:00
commit 21e5e68ae5
3 changed files with 161 additions and 121 deletions

View File

@ -262,18 +262,13 @@ void RestVocbaseBaseHandler::generate20x(
TRI_col_type_e type) {
VPackSlice slice = result.slice();
TRI_ASSERT(slice.isObject());
TRI_ASSERT(slice.isObject() || slice.isArray());
_response->setContentType("application/json; charset=utf-8");
_response->setHeader("etag", 4, "\"" + slice.get(TRI_VOC_ATTRIBUTE_REV).copyString() + "\"");
std::string escapedHandle(DocumentHelper::assembleDocumentId(
collectionName, slice.get(TRI_VOC_ATTRIBUTE_KEY).copyString(), true));
if (_request->compatibility() < 10400L) {
// pre-1.4 location header (e.g. /_api/document/xyz)
_response->setHeader("location", 8,
std::string(DOCUMENT_PATH + "/" + escapedHandle));
} else {
// 1.4+ location header (e.g. /_db/_system/_api/document/xyz)
if (slice.isObject()) {
_response->setHeader("etag", 4, "\"" + slice.get(TRI_VOC_ATTRIBUTE_REV).copyString() + "\"");
// pre 1.4 location headers withdrawn for >= 3.0
std::string escapedHandle(DocumentHelper::assembleDocumentId(
collectionName, slice.get(TRI_VOC_ATTRIBUTE_KEY).copyString(), true));
if (type == TRI_COL_TYPE_EDGE) {
_response->setHeader("location", 8,
std::string("/_db/" + _request->databaseName() +

View File

@ -737,40 +737,50 @@ OperationResult Transaction::insert(std::string const& collectionName,
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
}
if (value.isArray()) {
// multi-document variant is not yet implemented
THROW_ARANGO_EXCEPTION(TRI_ERROR_NOT_IMPLEMENTED);
}
// Validate Edges
if (isEdgeCollection(collectionName)) {
// Check _from
size_t split;
VPackSlice from = value.get(TRI_VOC_ATTRIBUTE_FROM);
if (!from.isString()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
std::string docId = from.copyString();
if (!TRI_ValidateDocumentIdKeyGenerator(docId.c_str(), &split)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
std::string cName = docId.substr(0, split);
if (TRI_COL_TYPE_UNKNOWN == resolver()->getCollectionType(cName)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
}
auto checkFrom = [&](VPackSlice const value) -> void {
size_t split;
VPackSlice from = value.get(TRI_VOC_ATTRIBUTE_FROM);
if (!from.isString()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
std::string docId = from.copyString();
if (!TRI_ValidateDocumentIdKeyGenerator(docId.c_str(), &split)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
std::string cName = docId.substr(0, split);
if (TRI_COL_TYPE_UNKNOWN == resolver()->getCollectionType(cName)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
}
};
// Check _to
VPackSlice to = value.get(TRI_VOC_ATTRIBUTE_TO);
if (!to.isString()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
docId = to.copyString();
if (!TRI_ValidateDocumentIdKeyGenerator(docId.c_str(), &split)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
cName = docId.substr(0, split);
if (TRI_COL_TYPE_UNKNOWN == resolver()->getCollectionType(cName)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
auto checkTo = [&](VPackSlice const value) -> void {
size_t split;
VPackSlice to = value.get(TRI_VOC_ATTRIBUTE_TO);
if (!to.isString()) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
std::string docId = to.copyString();
if (!TRI_ValidateDocumentIdKeyGenerator(docId.c_str(), &split)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE);
}
std::string cName = docId.substr(0, split);
if (TRI_COL_TYPE_UNKNOWN == resolver()->getCollectionType(cName)) {
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
}
};
if (value.isArray()) {
for (auto s : VPackArrayIterator(value)) {
checkFrom(s);
checkTo(s);
}
} else {
checkFrom(value);
checkTo(value);
}
}
@ -792,6 +802,12 @@ OperationResult Transaction::insert(std::string const& collectionName,
OperationResult Transaction::insertCoordinator(std::string const& collectionName,
VPackSlice const& value,
OperationOptions& options) {
if (value.isArray()) {
// must provide a document object
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
}
std::map<std::string, std::string> headers;
arangodb::rest::HttpResponse::HttpResponseCode responseCode;
std::map<std::string, std::string> resultHeaders;
@ -847,70 +863,83 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
return OperationResult(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
}
// add missing attributes for document (_id, _rev, _key)
VPackBuilder merge;
merge.openObject();
// generate a new tick value
TRI_voc_tick_t const revisionId = TRI_NewTickServer();
std::string keyString;
// TODO: clean this up
TRI_document_collection_t* document = documentCollection(trxCollection(cid));
auto key = value.get(TRI_VOC_ATTRIBUTE_KEY);
if (key.isNone()) {
// "_key" attribute not present in object
keyString = document->_keyGenerator->generate(revisionId);
merge.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(keyString));
} else if (!key.isString()) {
// "_key" present but wrong type
return OperationResult(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
} else {
keyString = key.copyString();
int res = document->_keyGenerator->validate(keyString, false);
if (res != TRI_ERROR_NO_ERROR) {
// invalid key value
return OperationResult(res);
}
}
// add _rev attribute
merge.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(revisionId)));
// add _id attribute
uint8_t* p = merge.add(TRI_VOC_ATTRIBUTE_ID, VPackValuePair(9ULL, VPackValueType::Custom));
*p++ = 0xf3; // custom type for _id
MarkerHelper::storeNumber<uint64_t>(p, cid, sizeof(uint64_t));
merge.close();
VPackBuilder toInsert = VPackCollection::merge(value, merge.slice(), false, false);
VPackSlice insertSlice = toInsert.slice();
if (orderDitch(trxCollection(cid)) == nullptr) {
return OperationResult(TRI_ERROR_OUT_OF_MEMORY);
}
TRI_doc_mptr_t mptr;
int res = document->insert(this, &insertSlice, &mptr, options, !isLocked(document, TRI_TRANSACTION_WRITE));
if (res != TRI_ERROR_NO_ERROR) {
return OperationResult(res);
}
if (options.silent) {
// no need to construct the result object
return OperationResult(TRI_ERROR_NO_ERROR);
}
TRI_ASSERT(mptr.getDataPtr() != nullptr);
VPackBuilder resultBuilder;
buildDocumentIdentity(resultBuilder, cid, keyString, mptr._rid, "");
return OperationResult(resultBuilder.steal(), nullptr, "", TRI_ERROR_NO_ERROR,
auto workForOneDocument = [&](VPackSlice const value) -> int {
// add missing attributes for document (_id, _rev, _key)
VPackBuilder merge;
merge.openObject();
// generate a new tick value
TRI_voc_tick_t const revisionId = TRI_NewTickServer();
std::string keyString;
auto key = value.get(TRI_VOC_ATTRIBUTE_KEY);
if (key.isNone()) {
// "_key" attribute not present in object
keyString = document->_keyGenerator->generate(revisionId);
merge.add(TRI_VOC_ATTRIBUTE_KEY, VPackValue(keyString));
} else if (!key.isString()) {
// "_key" present but wrong type
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
} else {
keyString = key.copyString();
int res = document->_keyGenerator->validate(keyString, false);
if (res != TRI_ERROR_NO_ERROR) {
// invalid key value
return res;
}
}
// add _rev attribute
merge.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(std::to_string(revisionId)));
// add _id attribute
uint8_t* p = merge.add(TRI_VOC_ATTRIBUTE_ID, VPackValuePair(9ULL, VPackValueType::Custom));
*p++ = 0xf3; // custom type for _id
MarkerHelper::storeNumber<uint64_t>(p, cid, sizeof(uint64_t));
merge.close();
VPackBuilder toInsert = VPackCollection::merge(value, merge.slice(), false, false);
VPackSlice insertSlice = toInsert.slice();
TRI_doc_mptr_t mptr;
int res = document->insert(this, &insertSlice, &mptr, options,
!isLocked(document, TRI_TRANSACTION_WRITE));
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
if (options.silent) {
// no need to construct the result object
return TRI_ERROR_NO_ERROR;
}
TRI_ASSERT(mptr.getDataPtr() != nullptr);
buildDocumentIdentity(resultBuilder, cid, keyString, mptr._rid, "");
return TRI_ERROR_NO_ERROR;
};
int res;
if (value.isArray()) {
VPackArrayBuilder b(&resultBuilder);
for (auto const s : VPackArrayIterator(value)) {
res = workForOneDocument(s);
if (res != TRI_ERROR_NO_ERROR) {
break;
}
}
} else {
res = workForOneDocument(value);
}
return OperationResult(resultBuilder.steal(), nullptr, "", res,
options.waitForSync);
}

View File

@ -1886,7 +1886,7 @@ static void JS_InsertVocbaseVPack(
options.waitForSync = ExtractWaitForSync(args, optsIdx + 1);
}
if (!args[docIdx]->IsObject() || args[docIdx]->IsArray()) {
if (!args[docIdx]->IsObject()) {
// invalid value type. must be a document
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
}
@ -1895,37 +1895,53 @@ static void JS_InsertVocbaseVPack(
VPackOptions vpackOptions = VPackOptions::Defaults;
vpackOptions.attributeExcludeHandler = basics::VelocyPackHelper::getExcludeHandler();
VPackBuilder builder(&vpackOptions);
v8::Handle<v8::Value> payload = args[0];
int res = TRI_V8ToVPack(isolate, builder, args[docIdx]->ToObject(), true);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
if (isEdgeCollection) {
// Just insert from and to. Check is done later.
std::string tmpId = ExtractIdString(isolate, args[0]);
if (tmpId.empty()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
auto doOneDocument = [&](v8::Handle<v8::Value> obj) -> void {
int res = TRI_V8ToVPack(isolate, builder, obj, true);
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);
}
builder.add(TRI_VOC_ATTRIBUTE_FROM, VPackValue(tmpId));
tmpId = ExtractIdString(isolate, args[1]);
if (tmpId.empty()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
if (isEdgeCollection) {
// Just insert from and to. Check is done later.
std::string tmpId = ExtractIdString(isolate, obj);
if (tmpId.empty()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
}
builder.add(TRI_VOC_ATTRIBUTE_FROM, VPackValue(tmpId));
tmpId = ExtractIdString(isolate, args[1]);
if (tmpId.empty()) {
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
}
builder.add(TRI_VOC_ATTRIBUTE_TO, VPackValue(tmpId));
}
builder.add(TRI_VOC_ATTRIBUTE_TO, VPackValue(tmpId));
}
builder.close();
builder.close();
};
if (payload->IsArray()) {
VPackArrayBuilder b(&builder);
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(payload);
uint32_t const n = array->Length();
for (uint32_t i = 0; i < n; ++i) {
doOneDocument(array->Get(i));
}
} else {
doOneDocument(payload);
}
// load collection
auto transactionContext = std::make_shared<V8TransactionContext>(collection->_vocbase, true);
SingleCollectionTransaction trx(transactionContext, collection->_cid, TRI_TRANSACTION_WRITE);
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
if (! payload->IsArray()) {
trx.addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION, false);
}
res = trx.begin();
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
TRI_V8_THROW_EXCEPTION(res);