mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'spdvpk' of https://github.com/arangodb/arangodb into spdvpk
This commit is contained in:
commit
d7bec3c343
|
@ -423,7 +423,7 @@ Slice Builder::getKey(std::string const& key) const {
|
|||
}
|
||||
|
||||
uint8_t* Builder::set(Value const& item) {
|
||||
auto const oldPos = _start + _pos;
|
||||
auto const oldPos = _pos;
|
||||
auto ctype = item.cType();
|
||||
|
||||
checkKeyIsString(item.valueType() == ValueType::String);
|
||||
|
@ -668,7 +668,7 @@ uint8_t* Builder::set(Value const& item) {
|
|||
"Cannot set a ValueType::Custom with this method");
|
||||
}
|
||||
}
|
||||
return oldPos;
|
||||
return _start + oldPos;
|
||||
}
|
||||
|
||||
uint8_t* Builder::set(Slice const& item) {
|
||||
|
@ -687,6 +687,8 @@ uint8_t* Builder::set(ValuePair const& pair) {
|
|||
// ValueType::Binary, or ValueType::Custom, which can be built
|
||||
// with two pieces of information
|
||||
|
||||
auto const oldPos = _pos;
|
||||
|
||||
checkKeyIsString(pair.valueType() == ValueType::String);
|
||||
|
||||
if (pair.valueType() == ValueType::Binary) {
|
||||
|
@ -694,7 +696,7 @@ uint8_t* Builder::set(ValuePair const& pair) {
|
|||
appendUInt(v, 0xbf);
|
||||
memcpy(_start + _pos, pair.getStart(), checkOverflow(v));
|
||||
_pos += v;
|
||||
return nullptr; // unused here
|
||||
return _start + oldPos;
|
||||
} else if (pair.valueType() == ValueType::String) {
|
||||
uint64_t size = pair.getSize();
|
||||
if (size > 126) {
|
||||
|
@ -802,12 +804,13 @@ uint8_t* Builder::add(ObjectIterator&& sub) {
|
|||
if (_keyWritten) {
|
||||
throw Exception(Exception::BuilderKeyAlreadyWritten);
|
||||
}
|
||||
auto const oldPos = _start + _pos;
|
||||
auto const oldPos = _pos;
|
||||
while (sub.valid()) {
|
||||
add(sub.key().copyString(), sub.value());
|
||||
add(sub.key());
|
||||
add(sub.value());
|
||||
sub.next();
|
||||
}
|
||||
return oldPos;
|
||||
return _start + oldPos;
|
||||
}
|
||||
|
||||
uint8_t* Builder::add(Value const& sub) { return addInternal<Value>(sub); }
|
||||
|
@ -832,12 +835,12 @@ uint8_t* Builder::add(ArrayIterator&& sub) {
|
|||
if (_start[tos] != 0x06 && _start[tos] != 0x13) {
|
||||
throw Exception(Exception::BuilderNeedOpenArray);
|
||||
}
|
||||
auto const oldPos = _start + _pos;
|
||||
auto const oldPos = _pos;
|
||||
while (sub.valid()) {
|
||||
add(sub.value());
|
||||
sub.next();
|
||||
}
|
||||
return oldPos;
|
||||
return _start + oldPos;
|
||||
}
|
||||
|
||||
static_assert(sizeof(double) == 8, "double is not 8 bytes");
|
||||
|
|
|
@ -2232,7 +2232,7 @@ AqlValue Functions::Neighbors(arangodb::aql::Query* query,
|
|||
size_t split;
|
||||
char const* str = vertexId.c_str();
|
||||
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(str, &split)) {
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(str, vertexId.size(), &split)) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD);
|
||||
}
|
||||
|
||||
|
|
|
@ -422,6 +422,10 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
|||
generateError(HttpResponse::BAD, res, "invalid document key");
|
||||
return;
|
||||
|
||||
case TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE:
|
||||
generateError(HttpResponse::BAD, res, "invalid edge attribute");
|
||||
return;
|
||||
|
||||
case TRI_ERROR_ARANGO_OUT_OF_KEYS:
|
||||
generateError(HttpResponse::SERVER_ERROR, res, "out of keys");
|
||||
return;
|
||||
|
@ -505,6 +509,10 @@ void RestVocbaseBaseHandler::generateTransactionError(
|
|||
generateError(HttpResponse::BAD, result.code, "invalid document key");
|
||||
return;
|
||||
|
||||
case TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE:
|
||||
generateError(HttpResponse::BAD, result.code, "invalid edge attribute");
|
||||
return;
|
||||
|
||||
case TRI_ERROR_ARANGO_OUT_OF_KEYS:
|
||||
generateError(HttpResponse::SERVER_ERROR, result.code, "out of keys");
|
||||
return;
|
||||
|
|
|
@ -686,44 +686,6 @@ OperationResult Transaction::insert(std::string const& collectionName,
|
|||
}
|
||||
|
||||
// Validate Edges
|
||||
if (isEdgeCollection(collectionName)) {
|
||||
// Check _from
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
// Check _to
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
||||
if (value.isArray()) {
|
||||
for (auto s : VPackArrayIterator(value)) {
|
||||
checkFrom(s);
|
||||
checkTo(s);
|
||||
}
|
||||
} else {
|
||||
checkFrom(value);
|
||||
checkTo(value);
|
||||
}
|
||||
}
|
||||
|
||||
OperationOptions optionsCopy = options;
|
||||
|
||||
if (ServerState::instance()->isCoordinator()) {
|
||||
|
@ -811,47 +773,8 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
|
|||
if (!value.isObject()) {
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||
}
|
||||
// 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
|
||||
DatafileHelper::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,
|
||||
int res = document->insert(this, value, &mptr, options,
|
||||
!isLocked(document, TRI_TRANSACTION_WRITE));
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
|
@ -865,6 +788,9 @@ OperationResult Transaction::insertLocal(std::string const& collectionName,
|
|||
|
||||
TRI_ASSERT(mptr.getDataPtr() != nullptr);
|
||||
|
||||
std::string keyString
|
||||
= VPackSlice(mptr.vpack()).get(TRI_VOC_ATTRIBUTE_KEY).copyString();
|
||||
|
||||
buildDocumentIdentity(resultBuilder, cid, keyString,
|
||||
mptr.revisionIdAsSlice(), VPackSlice(),
|
||||
nullptr, options.returnNew ? &mptr : nullptr);
|
||||
|
|
|
@ -85,7 +85,7 @@ static bool ParseDocumentHandle(v8::Handle<v8::Value> const arg,
|
|||
|
||||
// collection name / document key
|
||||
size_t split;
|
||||
if (TRI_ValidateDocumentIdKeyGenerator(*str, &split)) {
|
||||
if (TRI_ValidateDocumentIdKeyGenerator(*str, str.length(), &split)) {
|
||||
collectionName = std::string(*str, split);
|
||||
auto const length = str.length() - split - 1;
|
||||
auto buffer = new char[length + 1];
|
||||
|
@ -96,7 +96,7 @@ static bool ParseDocumentHandle(v8::Handle<v8::Value> const arg,
|
|||
}
|
||||
|
||||
// document key only
|
||||
if (TraditionalKeyGenerator::validateKey(*str)) {
|
||||
if (TraditionalKeyGenerator::validateKey(*str, str.length())) {
|
||||
auto const length = str.length();
|
||||
auto buffer = new char[length + 1];
|
||||
memcpy(buffer, *str, length);
|
||||
|
|
|
@ -231,23 +231,21 @@ TraditionalKeyGenerator::~TraditionalKeyGenerator() {}
|
|||
/// @brief validate a key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TraditionalKeyGenerator::validateKey(char const* key) {
|
||||
bool TraditionalKeyGenerator::validateKey(char const* key, size_t len) {
|
||||
unsigned char const* p = reinterpret_cast<unsigned char const*>(key);
|
||||
unsigned char const* s = p;
|
||||
size_t pos = 0;
|
||||
|
||||
while (true) {
|
||||
unsigned char c = *p;
|
||||
|
||||
if (c == '\0') {
|
||||
return ((p - s) > 0) && ((p - s) <= TRI_VOC_KEY_MAX_LENGTH);
|
||||
if (pos >= len || *p == '\0') {
|
||||
return (pos > 0) && (pos <= TRI_VOC_KEY_MAX_LENGTH);
|
||||
}
|
||||
|
||||
if (LookupTable[c]) {
|
||||
++p;
|
||||
continue;
|
||||
if (!LookupTable[*p]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
++p;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +269,7 @@ int TraditionalKeyGenerator::validate(std::string const& key, bool isRestore) {
|
|||
}
|
||||
|
||||
// validate user-supplied key
|
||||
if (!validateKey(key.c_str())) {
|
||||
if (!validateKey(key.c_str(), key.size())) {
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
|
||||
}
|
||||
|
||||
|
@ -320,22 +318,21 @@ AutoIncrementKeyGenerator::~AutoIncrementKeyGenerator() {}
|
|||
/// @brief validate a numeric key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool AutoIncrementKeyGenerator::validateKey(char const* key) {
|
||||
bool AutoIncrementKeyGenerator::validateKey(char const* key, size_t len) {
|
||||
char const* p = key;
|
||||
size_t pos = 0;
|
||||
|
||||
while (true) {
|
||||
char c = *p;
|
||||
|
||||
if (c == '\0') {
|
||||
return ((p - key) > 0) && ((p - key) <= TRI_VOC_KEY_MAX_LENGTH);
|
||||
if (pos >= len || *p == '\0') {
|
||||
return (pos > 0) && (pos <= TRI_VOC_KEY_MAX_LENGTH);
|
||||
}
|
||||
|
||||
if (c >= '0' && c <= '9') {
|
||||
++p;
|
||||
continue;
|
||||
if (*p < '0' || *p > '9') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
++p;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,7 +380,7 @@ int AutoIncrementKeyGenerator::validate(std::string const& key,
|
|||
}
|
||||
|
||||
// validate user-supplied key
|
||||
if (!validateKey(key.c_str())) {
|
||||
if (!validateKey(key.c_str(), key.size())) {
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
|
||||
}
|
||||
|
||||
|
@ -428,9 +425,15 @@ void AutoIncrementKeyGenerator::toVelocyPack(VPackBuilder& builder) const {
|
|||
/// @brief validate a document id (collection name + / + document key)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_ValidateDocumentIdKeyGenerator(char const* key, size_t* split) {
|
||||
bool TRI_ValidateDocumentIdKeyGenerator(char const* key, size_t len,
|
||||
size_t* split) {
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
char const* p = key;
|
||||
char c = *p;
|
||||
size_t pos = 0;
|
||||
|
||||
// extract collection name
|
||||
if (!(c == '_' || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') ||
|
||||
|
@ -439,13 +442,18 @@ bool TRI_ValidateDocumentIdKeyGenerator(char const* key, size_t* split) {
|
|||
}
|
||||
|
||||
++p;
|
||||
++pos;
|
||||
|
||||
while (true) {
|
||||
if (pos >= len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c = *p;
|
||||
|
||||
if (c == '_' || c == '-' || (c >= '0' && c <= '9') ||
|
||||
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {
|
||||
++p;
|
||||
++pos;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -456,14 +464,15 @@ bool TRI_ValidateDocumentIdKeyGenerator(char const* key, size_t* split) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (static_cast<size_t>(p - key) > TRI_COL_NAME_LENGTH) {
|
||||
if (pos > TRI_COL_NAME_LENGTH) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// store split position
|
||||
*split = p - key;
|
||||
*split = pos;
|
||||
++p;
|
||||
++pos;
|
||||
|
||||
// validate document key
|
||||
return TraditionalKeyGenerator::validateKey(p);
|
||||
return TraditionalKeyGenerator::validateKey(p, len - pos);
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ class TraditionalKeyGenerator : public KeyGenerator {
|
|||
/// @brief validate a key
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool validateKey(char const* key);
|
||||
static bool validateKey(char const* key, size_t len);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -210,7 +210,7 @@ class AutoIncrementKeyGenerator : public KeyGenerator {
|
|||
/// @brief validate a key
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool validateKey(char const* key);
|
||||
static bool validateKey(char const* key, size_t len);
|
||||
|
||||
public:
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -259,6 +259,6 @@ class AutoIncrementKeyGenerator : public KeyGenerator {
|
|||
/// @brief validate a document id (collection name + / + document key)
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool TRI_ValidateDocumentIdKeyGenerator(char const*, size_t*);
|
||||
bool TRI_ValidateDocumentIdKeyGenerator(char const*, size_t, size_t*);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,7 +39,7 @@ arangodb::traverser::VertexId arangodb::traverser::IdStringToVertexId(
|
|||
size_t split;
|
||||
char const* str = vertex.c_str();
|
||||
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(str, &split)) {
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(str, vertex.size(), &split)) {
|
||||
THROW_ARANGO_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_HANDLE_BAD);
|
||||
}
|
||||
|
||||
|
|
|
@ -3272,29 +3272,45 @@ int TRI_document_collection_t::insert(Transaction* trx, VPackSlice const slice,
|
|||
bool lock) {
|
||||
|
||||
if (_info.type() == TRI_COL_TYPE_EDGE) {
|
||||
// _from:
|
||||
VPackSlice s = slice.get(TRI_VOC_ATTRIBUTE_FROM);
|
||||
if (!s.isString()) {
|
||||
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
|
||||
}
|
||||
VPackValueLength len;
|
||||
char const* docId = s.getString(len);
|
||||
size_t split;
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(docId, len, &split)) {
|
||||
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
|
||||
}
|
||||
// _to:
|
||||
s = slice.get(TRI_VOC_ATTRIBUTE_TO);
|
||||
if (!s.isString()) {
|
||||
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
|
||||
}
|
||||
docId = s.getString(len);
|
||||
if (!TRI_ValidateDocumentIdKeyGenerator(docId, len, &split)) {
|
||||
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t hash = 0;
|
||||
VPackBuilder builder;
|
||||
int res = newObjectForInsert(trx, slice, hash, builder);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
VPackSlice newSlice = builder.slice();
|
||||
|
||||
TRI_ASSERT(mptr != nullptr);
|
||||
mptr->setDataPtr(nullptr);
|
||||
|
||||
VPackSlice const key(slice.get(TRI_VOC_ATTRIBUTE_KEY));
|
||||
uint64_t const hash = key.hash();
|
||||
|
||||
std::unique_ptr<arangodb::wal::Marker> marker;
|
||||
if (options.recoveryMarker == nullptr) {
|
||||
marker.reset(createVPackInsertMarker(trx, slice));
|
||||
marker.reset(createVPackInsertMarker(trx, newSlice));
|
||||
}
|
||||
|
||||
TRI_voc_tick_t markerTick = 0;
|
||||
int res;
|
||||
// now insert into indexes
|
||||
{
|
||||
TRI_IF_FAILURE("InsertDocumentNoLock") {
|
||||
|
@ -4034,6 +4050,47 @@ int TRI_document_collection_t::deleteSecondaryIndexes(
|
|||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief new object for insert, computes the hash of the key
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int TRI_document_collection_t::newObjectForInsert(
|
||||
Transaction* trx,
|
||||
VPackSlice const& value,
|
||||
uint64_t& hash,
|
||||
VPackBuilder& builder) {
|
||||
// insert
|
||||
{ VPackObjectBuilder guard(&builder);
|
||||
|
||||
TRI_SanitizeObject(value, builder);
|
||||
uint8_t* p = builder.add(TRI_VOC_ATTRIBUTE_ID,
|
||||
VPackValuePair(9ULL, VPackValueType::Custom));
|
||||
*p++ = 0xf3; // custom type for _id
|
||||
DatafileHelper::StoreNumber<uint64_t>(p, _info.id(), sizeof(uint64_t));
|
||||
VPackSlice s = value.get(TRI_VOC_ATTRIBUTE_KEY);
|
||||
TRI_voc_tick_t const newRev = TRI_NewTickServer();
|
||||
if (s.isNone()) {
|
||||
std::string keyString = _keyGenerator->generate(newRev);
|
||||
uint8_t* where = builder.add(TRI_VOC_ATTRIBUTE_KEY,
|
||||
VPackValue(keyString));
|
||||
s = VPackSlice(where); // point to newly built value, the string
|
||||
} else if (!s.isString()) {
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_KEY_BAD;
|
||||
} else {
|
||||
std::string keyString = s.copyString();
|
||||
int res = _keyGenerator->validate(keyString, false);
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
builder.add(TRI_VOC_ATTRIBUTE_KEY, s);
|
||||
}
|
||||
hash = s.hash();
|
||||
std::string rev = std::to_string(newRev);
|
||||
builder.add(TRI_VOC_ATTRIBUTE_REV, VPackValue(rev));
|
||||
}
|
||||
return TRI_ERROR_NO_ERROR;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief new object for replace, oldValue must have _key and _id correctly
|
||||
/// set.
|
||||
|
@ -4044,7 +4101,6 @@ VPackBuilder TRI_document_collection_t::newObjectForReplace(
|
|||
VPackSlice const& oldValue,
|
||||
VPackSlice const& newValue,
|
||||
std::string const& rev) {
|
||||
// replace
|
||||
VPackBuilder builder;
|
||||
{ VPackObjectBuilder guard(&builder);
|
||||
|
||||
|
|
|
@ -253,6 +253,16 @@ struct TRI_document_collection_t : public TRI_collection_t {
|
|||
int deleteSecondaryIndexes(arangodb::Transaction*, TRI_doc_mptr_t const*,
|
||||
bool);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief new object for insert, value must have _key set correctly.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int newObjectForInsert(
|
||||
arangodb::Transaction* trx,
|
||||
arangodb::velocypack::Slice const& value,
|
||||
uint64_t& hash,
|
||||
arangodb::velocypack::Builder& builder);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief new object for Replace
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -2030,6 +2030,274 @@ function DatabaseDocumentSuite () {
|
|||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief test suite: returnNew and returnOld options
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function DatabaseDocumentSuiteReturnStuff () {
|
||||
'use strict';
|
||||
var cn = "UnitTestsCollectionBasics";
|
||||
var ERRORS = require("internal").errors;
|
||||
var collection = null;
|
||||
|
||||
return {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief set up
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
setUp : function () {
|
||||
db._drop(cn);
|
||||
collection = db._create(cn, { waitForSync : false });
|
||||
|
||||
collection.load();
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief tear down
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
tearDown : function () {
|
||||
collection.drop();
|
||||
wait(0.0);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief create with and without returnNew
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testCreateReturnNew : function () {
|
||||
var res = collection.insert({"Hallo":12});
|
||||
assertTypeOf("object", res);
|
||||
assertEqual(3, Object.keys(res).length);
|
||||
assertTypeOf("string", res._id);
|
||||
assertTypeOf("string", res._key);
|
||||
assertTypeOf("string", res._rev);
|
||||
|
||||
// Now with returnNew: true
|
||||
res = collection.insert({"Hallo":12}, {returnNew: true});
|
||||
assertTypeOf("object", res);
|
||||
assertEqual(4, Object.keys(res).length);
|
||||
assertTypeOf("string", res._id);
|
||||
assertTypeOf("string", res._key);
|
||||
assertTypeOf("string", res._rev);
|
||||
assertTypeOf("object", res["new"]);
|
||||
assertEqual(12, res["new"].Hallo);
|
||||
assertEqual(4, Object.keys(res["new"]).length);
|
||||
|
||||
// Now with returnNew: false
|
||||
res = collection.insert({"Hallo":12}, {returnNew: false});
|
||||
assertTypeOf("object", res);
|
||||
assertEqual(3, Object.keys(res).length);
|
||||
assertTypeOf("string", res._id);
|
||||
assertTypeOf("string", res._key);
|
||||
assertTypeOf("string", res._rev);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief remove with and without returnOld
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testRemoveReturnOld : function () {
|
||||
var res = collection.insert({"Hallo":12});
|
||||
var res2 = collection.remove(res._key);
|
||||
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(3, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnOld: true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.remove(res._key, {returnOld: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2.old);
|
||||
assertEqual(12, res2.old.Hallo);
|
||||
assertEqual(4, Object.keys(res2.old).length);
|
||||
|
||||
// Now with returnOld: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.remove(res._key, {returnOld: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(3, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replace with and without returnOld and returnNew
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testReplaceReturnOldNew : function () {
|
||||
var res = collection.insert({"Hallo":12});
|
||||
var res2 = collection.replace(res._key,{"Hallo":13});
|
||||
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnOld: true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.replace(res._key, {"Hallo":13}, {returnOld: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(5, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2.old);
|
||||
assertEqual(12, res2.old.Hallo);
|
||||
assertEqual(4, Object.keys(res2.old).length);
|
||||
|
||||
// Now with returnOld: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.replace(res._key, {"Hallo":14}, {returnOld: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnNew: true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.replace(res._key, {"Hallo":14}, {returnNew: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(5, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2["new"]);
|
||||
assertEqual(14, res2["new"].Hallo);
|
||||
assertEqual(4, Object.keys(res2["new"]).length);
|
||||
|
||||
// Now with returnOld: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.replace(res._key, {"Hallo":15}, {returnNew: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnNew: true and returnOld:true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.replace(res._key, {"Hallo":16},
|
||||
{returnNew: true, returnOld: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(6, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2.old);
|
||||
assertTypeOf("object", res2["new"]);
|
||||
assertEqual(16, res2["new"].Hallo);
|
||||
assertEqual(12, res2.old.Hallo);
|
||||
assertEqual(4, Object.keys(res2["new"]).length);
|
||||
assertEqual(4, Object.keys(res2.old).length);
|
||||
|
||||
// Now with returnOld: false and returnNew: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.replace(res._key, {"Hallo":15},
|
||||
{returnNew: false, returnOld: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief update with and without returnOld and returnNew
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
testUpdateReturnOldNew : function () {
|
||||
var res = collection.insert({"Hallo":12});
|
||||
var res2 = collection.update(res._key,{"Hallo":13});
|
||||
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnOld: true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.update(res._key, {"Hallo":13}, {returnOld: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(5, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2.old);
|
||||
assertEqual(12, res2.old.Hallo);
|
||||
assertEqual(4, Object.keys(res2.old).length);
|
||||
|
||||
// Now with returnOld: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.update(res._key, {"Hallo":14}, {returnOld: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnNew: true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.update(res._key, {"Hallo":14}, {returnNew: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(5, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2["new"]);
|
||||
assertEqual(14, res2["new"].Hallo);
|
||||
assertEqual(4, Object.keys(res2["new"]).length);
|
||||
|
||||
// Now with returnOld: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.update(res._key, {"Hallo":15}, {returnNew: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
|
||||
// Now with returnNew: true and returnOld:true
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.update(res._key, {"Hallo":16},
|
||||
{returnNew: true, returnOld: true});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(6, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
assertTypeOf("object", res2.old);
|
||||
assertTypeOf("object", res2["new"]);
|
||||
assertEqual(16, res2["new"].Hallo);
|
||||
assertEqual(12, res2.old.Hallo);
|
||||
assertEqual(4, Object.keys(res2["new"]).length);
|
||||
assertEqual(4, Object.keys(res2.old).length);
|
||||
|
||||
// Now with returnOld: false and returnNew: false
|
||||
res = collection.insert({"Hallo":12});
|
||||
res2 = collection.update(res._key, {"Hallo":15},
|
||||
{returnNew: false, returnOld: false});
|
||||
assertTypeOf("object", res2);
|
||||
assertEqual(4, Object.keys(res2).length);
|
||||
assertTypeOf("string", res2._id);
|
||||
assertTypeOf("string", res2._key);
|
||||
assertTypeOf("string", res2._rev);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief executes the test suites
|
||||
|
@ -2041,5 +2309,7 @@ jsunity.run(CollectionDocumentSuite);
|
|||
jsunity.run(DatabaseDocumentSuiteErrorHandling);
|
||||
jsunity.run(DatabaseDocumentSuite);
|
||||
|
||||
jsunity.run(DatabaseDocumentSuiteReturnStuff);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
|
|
Loading…
Reference in New Issue