1
0
Fork 0

document creation

This commit is contained in:
jsteemann 2015-11-17 01:46:58 +01:00
parent 5f25de1710
commit f5e71197ce
8 changed files with 176 additions and 148 deletions

View File

@ -1,47 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief Library to build up VPack documents.
///
/// DISCLAIMER
///
/// Copyright 2015 ArangoDB GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Jan Steemann
/// @author Copyright 2015, ArangoDB GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef VELOCYPACK_DUMP_H
#define VELOCYPACK_DUMP_H 1
#include <string>
#include "velocypack/velocypack-common.h"
#include "velocypack/Buffer.h"
#include "velocypack/Dumper.h"
namespace arangodb {
namespace velocypack {
// some alias types for easier usage
typedef Dumper<CharBuffer, false> BufferDumper;
typedef Dumper<std::string, false> StringDumper;
typedef Dumper<std::string, true> StringPrettyDumper;
} // namespace arangodb::velocypack
} // namespace arangodb
#endif

View File

@ -114,6 +114,8 @@ namespace arangodb {
dumpString(str.c_str(), str.size());
_sink->push_back('"');
}
void appendUInt (uint64_t);
private:

View File

@ -39,32 +39,36 @@ namespace arangodb {
int fpconv_dtoa (double fp, char dest[24]);
}
};
void Dumper::appendUInt (uint64_t v) {
if (10000000000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000000000ULL) % 10); }
if ( 1000000000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000000000ULL) % 10); }
if ( 100000000000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000000000ULL) % 10); }
if ( 10000000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000000ULL) % 10); }
if ( 1000000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000000ULL) % 10); }
if ( 100000000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000000ULL) % 10); }
if ( 10000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000ULL) % 10); }
if ( 1000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000ULL) % 10); }
if ( 100000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000ULL) % 10); }
if ( 10000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000ULL) % 10); }
if ( 1000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000ULL) % 10); }
if ( 100000000ULL <= v) { _sink->push_back('0' + (v / 100000000ULL) % 10); }
if ( 10000000ULL <= v) { _sink->push_back('0' + (v / 10000000ULL) % 10); }
if ( 1000000ULL <= v) { _sink->push_back('0' + (v / 1000000ULL) % 10); }
if ( 100000ULL <= v) { _sink->push_back('0' + (v / 100000ULL) % 10); }
if ( 10000ULL <= v) { _sink->push_back('0' + (v / 10000ULL) % 10); }
if ( 1000ULL <= v) { _sink->push_back('0' + (v / 1000ULL) % 10); }
if ( 100ULL <= v) { _sink->push_back('0' + (v / 100ULL) % 10); }
if ( 10ULL <= v) { _sink->push_back('0' + (v / 10ULL) % 10); }
_sink->push_back('0' + (v % 10));
}
void Dumper::dumpInteger (Slice const* slice) {
if (slice->isType(ValueType::UInt)) {
uint64_t v = slice->getUInt();
if (10000000000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000000000ULL) % 10); }
if ( 1000000000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000000000ULL) % 10); }
if ( 100000000000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000000000ULL) % 10); }
if ( 10000000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000000ULL) % 10); }
if ( 1000000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000000ULL) % 10); }
if ( 100000000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000000ULL) % 10); }
if ( 10000000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000000ULL) % 10); }
if ( 1000000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000000ULL) % 10); }
if ( 100000000000ULL <= v) { _sink->push_back('0' + (v / 100000000000ULL) % 10); }
if ( 10000000000ULL <= v) { _sink->push_back('0' + (v / 10000000000ULL) % 10); }
if ( 1000000000ULL <= v) { _sink->push_back('0' + (v / 1000000000ULL) % 10); }
if ( 100000000ULL <= v) { _sink->push_back('0' + (v / 100000000ULL) % 10); }
if ( 10000000ULL <= v) { _sink->push_back('0' + (v / 10000000ULL) % 10); }
if ( 1000000ULL <= v) { _sink->push_back('0' + (v / 1000000ULL) % 10); }
if ( 100000ULL <= v) { _sink->push_back('0' + (v / 100000ULL) % 10); }
if ( 10000ULL <= v) { _sink->push_back('0' + (v / 10000ULL) % 10); }
if ( 1000ULL <= v) { _sink->push_back('0' + (v / 1000ULL) % 10); }
if ( 100ULL <= v) { _sink->push_back('0' + (v / 100ULL) % 10); }
if ( 10ULL <= v) { _sink->push_back('0' + (v / 10ULL) % 10); }
_sink->push_back('0' + (v % 10));
appendUInt(v);
}
else if (slice->isType(ValueType::Int)) {
int64_t v = slice->getInt();

View File

@ -28,15 +28,18 @@
////////////////////////////////////////////////////////////////////////////////
#include "Storage/Options.h"
#include "Basics/Exceptions.h"
#include "Utils/CollectionNameResolver.h"
#include "VocBase/voc-types.h"
using namespace arangodb;
// global options used when converting JSON into a document
VPackOptions JsonToDocumentOptions;
VPackOptions StorageOptions::JsonToDocumentTemplate;
// global options used when converting documents into JSON
VPackOptions DocumentToJsonOptions;
VPackOptions StorageOptions::DocumentToJsonTemplate;
// global options used for other conversions
VPackOptions NonDocumentOptions;
VPackOptions StorageOptions::NonDocumentTemplate;
struct ExcludeHandlerImpl : public VPackAttributeExcludeHandler {
bool shouldExclude (VPackSlice const& key, int nesting) override final {
@ -62,16 +65,45 @@ struct ExcludeHandlerImpl : public VPackAttributeExcludeHandler {
};
struct CustomTypeHandlerImpl : public VPackCustomTypeHandler {
CustomTypeHandlerImpl (triagens::arango::CollectionNameResolver const* resolver,
TRI_voc_cid_t cid)
: resolver(resolver),
cid(cid) {
}
void toJson (VPackSlice const& value, VPackDumper* dumper, VPackSlice const& base) {
if (value.head() == 0xf0) {
// _id
// TODO
return;
if (! base.isObject()) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid value type");
}
char buffer[512]; // TODO: check if size is appropriate
size_t len = resolver->getCollectionName(&buffer[0], cid);
buffer[len] = '/';
VPackSlice key = base.get("_key");
VPackValueLength keyLength;
char const* p = key.getString(keyLength);
if (p == nullptr) {
THROW_ARANGO_EXCEPTION_MESSAGE(TRI_ERROR_INTERNAL, "invalid _key value");
}
memcpy(&buffer[len + 1], p, keyLength);
dumper->appendString(&buffer[0], len + 1 + keyLength);
}
if (value.head() == 0xf1) {
// _rev
// TODO
uint64_t rev = 0;
uint8_t const* start = value.start() + 1;
uint8_t const* end = start + value.byteSize();
do {
rev <<= 8;
rev += static_cast<uint64_t>(*start++);
}
while (start < end);
dumper->sink()->push_back('"');
dumper->appendUInt(rev);
dumper->sink()->push_back('"');
return;
}
@ -101,12 +133,13 @@ struct CustomTypeHandlerImpl : public VPackCustomTypeHandler {
}
throw "unknown type!";
}
triagens::arango::CollectionNameResolver const* resolver;
TRI_voc_cid_t cid;
};
StorageOptions::StorageOptions ()
: _translator(new VPackAttributeTranslator),
_customTypeHandler(new CustomTypeHandlerImpl),
_excludeHandler(new ExcludeHandlerImpl) {
// these attribute names will be translated into short integer values
@ -118,38 +151,49 @@ StorageOptions::StorageOptions ()
_translator->seal();
// set options for JSON to document conversion
JsonToDocumentOptions.buildUnindexedArrays = false;
JsonToDocumentOptions.buildUnindexedObjects = false;
JsonToDocumentOptions.checkAttributeUniqueness = true;
JsonToDocumentOptions.sortAttributeNames = true;
JsonToDocumentOptions.attributeTranslator = _translator.get();
JsonToDocumentOptions.customTypeHandler = _customTypeHandler.get();
JsonToDocumentOptions.attributeExcludeHandler = _excludeHandler.get();
JsonToDocumentTemplate.buildUnindexedArrays = false;
JsonToDocumentTemplate.buildUnindexedObjects = false;
JsonToDocumentTemplate.checkAttributeUniqueness = true;
JsonToDocumentTemplate.sortAttributeNames = true;
JsonToDocumentTemplate.attributeTranslator = _translator.get();
JsonToDocumentTemplate.customTypeHandler = nullptr;
JsonToDocumentTemplate.attributeExcludeHandler = _excludeHandler.get();
// set options for document to JSON conversion
DocumentToJsonOptions.prettyPrint = false;
DocumentToJsonOptions.escapeForwardSlashes = true;
DocumentToJsonOptions.unsupportedTypeBehavior = VPackOptions::FailOnUnsupportedType;
DocumentToJsonOptions.attributeTranslator = _translator.get();
DocumentToJsonOptions.customTypeHandler = _customTypeHandler.get();
DocumentToJsonOptions.attributeExcludeHandler = nullptr;
DocumentToJsonTemplate.attributeTranslator = _translator.get();
DocumentToJsonTemplate.customTypeHandler = nullptr;
DocumentToJsonTemplate.attributeExcludeHandler = nullptr;
DocumentToJsonTemplate.prettyPrint = false;
DocumentToJsonTemplate.escapeForwardSlashes = true;
DocumentToJsonTemplate.unsupportedTypeBehavior = VPackOptions::FailOnUnsupportedType;
NonDocumentOptions.prettyPrint = false;
NonDocumentOptions.escapeForwardSlashes = true;
NonDocumentOptions.sortAttributeNames = false;
NonDocumentOptions.buildUnindexedArrays = true;
NonDocumentOptions.buildUnindexedObjects = true;
NonDocumentOptions.checkAttributeUniqueness = false;
NonDocumentOptions.unsupportedTypeBehavior = VPackOptions::FailOnUnsupportedType;
NonDocumentOptions.attributeTranslator = nullptr;
NonDocumentOptions.customTypeHandler = nullptr;
NonDocumentOptions.attributeExcludeHandler = nullptr;
// bool keepTopLevelOpen = false;
// non-document options
NonDocumentTemplate.buildUnindexedArrays = true;
NonDocumentTemplate.buildUnindexedObjects = true;
NonDocumentTemplate.checkAttributeUniqueness = false;
NonDocumentTemplate.sortAttributeNames = false;
NonDocumentTemplate.attributeTranslator = nullptr;
NonDocumentTemplate.customTypeHandler = nullptr;
NonDocumentTemplate.attributeExcludeHandler = nullptr;
NonDocumentTemplate.prettyPrint = false;
NonDocumentTemplate.escapeForwardSlashes = true;
NonDocumentTemplate.unsupportedTypeBehavior = VPackOptions::FailOnUnsupportedType;
}
StorageOptions::~StorageOptions () {
}
VPackOptions StorageOptions::getDocumentToJsonTemplate () {
return DocumentToJsonTemplate;
}
VPackOptions StorageOptions::getJsonToDocumentTemplate () {
return JsonToDocumentTemplate;
}
VPackOptions StorageOptions::getNonDocumentTemplate () {
return NonDocumentTemplate;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE

View File

@ -42,15 +42,18 @@ namespace arangodb {
StorageOptions (StorageOptions const&) = delete;
StorageOptions& operator= (StorageOptions const&) = delete;
static VPackOptions getDocumentToJsonTemplate ();
static VPackOptions getJsonToDocumentTemplate ();
static VPackOptions getNonDocumentTemplate ();
private:
std::unique_ptr<VPackAttributeTranslator> _translator;
std::unique_ptr<VPackCustomTypeHandler> _customTypeHandler;
std::unique_ptr<VPackAttributeExcludeHandler> _excludeHandler;
static VPackOptions JsonToDocumentOptions;
static VPackOptions DocumentToJsonOptions;
static VPackOptions NonDocumentOptions;
static VPackOptions JsonToDocumentTemplate;
static VPackOptions DocumentToJsonTemplate;
static VPackOptions NonDocumentTemplate;
};
}

View File

@ -34,6 +34,7 @@
#include "Basics/json-utilities.h"
#include "Cluster/ClusterMethods.h"
#include "Indexes/PrimaryIndex.h"
#include "Storage/Options.h"
#include "Utils/transactions.h"
#include "Utils/V8ResolverGuard.h"
#include "Utils/V8TransactionContext.h"
@ -1005,11 +1006,23 @@ static void InsertVocbaseCol (TRI_vocbase_col_t* col,
TRI_V8_THROW_EXCEPTION(TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID);
}
VPackBuilder builder = TRI_V8ToVPack(isolate, args[0]->ToObject());
VPackOptions vOptions = arangodb::StorageOptions::getDocumentToJsonTemplate();
VPackBuilder builder(&vOptions);
int res2 = TRI_V8ToVPack(isolate, builder, args[0]->ToObject(), true);
if (res2 || builder.hasKey("_key")) {
}
else {
}
builder.close();
VPackSlice slice(builder.slice());
for (auto const& it : VPackObjectIterator(slice)) {
std::cout << "KEY: " << it.key.copyString() << "\n";
}
//std::cout << "GOT: " << VPackHexDump(slice) << "\n\n";
// std::cout << "GOT: " << VPackHexDump(slice) << "\n\n";
// set document key

View File

@ -128,19 +128,31 @@ v8::Handle<v8::Value> TRI_VPackToV8 (v8::Isolate* isolate,
}
}
struct BuilderContext {
BuilderContext (v8::Isolate* isolate, VPackBuilder& builder, bool keepTopLevelOpen)
: isolate(isolate), builder(builder), keepTopLevelOpen(keepTopLevelOpen) {
}
v8::Isolate* isolate;
VPackBuilder& builder;
std::set<int> seenHashes;
std::vector<v8::Handle<v8::Object>> seenObjects;
bool keepTopLevelOpen;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief adds a VPackValue to either an array or an object
////////////////////////////////////////////////////////////////////////////////
static void AddValue (VPackBuilder& builder,
static void AddValue (BuilderContext& context,
std::string const& attributeName,
bool inObject,
VPackValue const& value) {
if (inObject) {
builder.add(attributeName, value);
context.builder.add(attributeName, value);
}
else {
builder.add(value);
context.builder.add(value);
}
}
@ -148,29 +160,27 @@ static void AddValue (VPackBuilder& builder,
/// @brief convert a V8 value to a VPack value
////////////////////////////////////////////////////////////////////////////////
static int V8ToVPack (v8::Isolate* isolate,
VPackBuilder& builder,
static int V8ToVPack (BuilderContext& context,
v8::Handle<v8::Value> const parameter,
std::set<int>& seenHashes,
std::vector<v8::Handle<v8::Object>>& seenObjects,
std::string const& attributeName,
bool inObject) {
v8::Isolate* isolate = context.isolate;
v8::HandleScope scope(isolate);
if (parameter->IsNull()) {
AddValue(builder, attributeName, inObject, VPackValue(VPackValueType::Null));
AddValue(context, attributeName, inObject, VPackValue(VPackValueType::Null));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsBoolean()) {
v8::Handle<v8::Boolean> booleanParameter = parameter->ToBoolean();
AddValue(builder, attributeName, inObject, VPackValue(booleanParameter->Value()));
AddValue(context, attributeName, inObject, VPackValue(booleanParameter->Value()));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsNumber()) {
v8::Handle<v8::Number> numberParameter = parameter->ToNumber();
AddValue(builder, attributeName, inObject, VPackValue(numberParameter->Value()));
AddValue(context, attributeName, inObject, VPackValue(numberParameter->Value()));
return TRI_ERROR_NO_ERROR;
}
@ -182,37 +192,37 @@ static int V8ToVPack (v8::Isolate* isolate,
return TRI_ERROR_OUT_OF_MEMORY;
}
AddValue(builder, attributeName, inObject, VPackValue(*str));
AddValue(context, attributeName, inObject, VPackValue(*str));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsArray()) {
v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(parameter);
AddValue(builder, attributeName, inObject, VPackValue(VPackValueType::Array));
AddValue(context, attributeName, inObject, VPackValue(VPackValueType::Array));
uint32_t const n = array->Length();
for (uint32_t i = 0; i < n; ++i) {
// get address of next element
int res = V8ToVPack(isolate, builder, array->Get(i), seenHashes, seenObjects, "", false);
int res = V8ToVPack(context, array->Get(i), "", false);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
}
builder.close();
context.builder.close();
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsObject()) {
if (parameter->IsBooleanObject()) {
AddValue(builder, attributeName, inObject, VPackValue(v8::Handle<v8::BooleanObject>::Cast(parameter)->BooleanValue()));
AddValue(context, attributeName, inObject, VPackValue(v8::Handle<v8::BooleanObject>::Cast(parameter)->BooleanValue()));
return TRI_ERROR_NO_ERROR;
}
if (parameter->IsNumberObject()) {
AddValue(builder, attributeName, inObject, VPackValue(v8::Handle<v8::NumberObject>::Cast(parameter)->NumberValue()));
AddValue(context, attributeName, inObject, VPackValue(v8::Handle<v8::NumberObject>::Cast(parameter)->NumberValue()));
return TRI_ERROR_NO_ERROR;
}
@ -224,7 +234,7 @@ static int V8ToVPack (v8::Isolate* isolate,
return TRI_ERROR_OUT_OF_MEMORY;
}
AddValue(builder, attributeName, inObject, VPackValue(*str));
AddValue(context, attributeName, inObject, VPackValue(*str));
return TRI_ERROR_NO_ERROR;
}
@ -256,7 +266,7 @@ static int V8ToVPack (v8::Isolate* isolate,
}
// this passes ownership for the utf8 string to the JSON object
AddValue(builder, attributeName, inObject, VPackValue(*str));
AddValue(context, attributeName, inObject, VPackValue(*str));
return TRI_ERROR_NO_ERROR;
}
}
@ -266,10 +276,10 @@ static int V8ToVPack (v8::Isolate* isolate,
int hash = o->GetIdentityHash();
if (seenHashes.find(hash) != seenHashes.end()) {
if (context.seenHashes.find(hash) != context.seenHashes.end()) {
// LOG_TRACE("found hash %d", hash);
for (auto& it : seenObjects) {
for (auto& it : context.seenObjects) {
if (parameter->StrictEquals(it)) {
// object is recursive
return TRI_ERROR_BAD_PARAMETER;
@ -277,15 +287,15 @@ static int V8ToVPack (v8::Isolate* isolate,
}
}
else {
seenHashes.emplace(hash);
context.seenHashes.emplace(hash);
}
seenObjects.emplace_back(o);
context.seenObjects.emplace_back(o);
v8::Handle<v8::Array> names = o->GetOwnPropertyNames();
uint32_t const n = names->Length();
AddValue(builder, attributeName, inObject, VPackValue(VPackValueType::Object));
AddValue(context, attributeName, inObject, VPackValue(VPackValueType::Object));
for (uint32_t i = 0; i < n; ++i) {
// process attribute name
@ -296,7 +306,7 @@ static int V8ToVPack (v8::Isolate* isolate,
return TRI_ERROR_OUT_OF_MEMORY;
}
int res = V8ToVPack(isolate, builder, o->Get(key), seenHashes, seenObjects, *str, true);
int res = V8ToVPack(context, o->Get(key), *str, true);
if (res != TRI_ERROR_NO_ERROR) {
// to mimic behavior of previous ArangoDB versions, we need to silently ignore this error
@ -305,8 +315,10 @@ static int V8ToVPack (v8::Isolate* isolate,
}
}
seenObjects.pop_back();
builder.close();
context.seenObjects.pop_back();
if (! context.keepTopLevelOpen || ! context.seenObjects.empty()) {
context.builder.close();
}
return TRI_ERROR_NO_ERROR;
}
@ -317,20 +329,15 @@ static int V8ToVPack (v8::Isolate* isolate,
/// @brief convert a V8 value to VPack value
////////////////////////////////////////////////////////////////////////////////
VPackBuilder TRI_V8ToVPack (v8::Isolate* isolate,
v8::Handle<v8::Value> const parameter) {
int TRI_V8ToVPack (v8::Isolate* isolate,
VPackBuilder& builder,
v8::Handle<v8::Value> const value,
bool keepTopLevelOpen) {
VPackBuilder builder;
BuilderContext context(isolate, builder, keepTopLevelOpen);
int res = V8ToVPack(context, value, "", false);
std::set<int> seenHashes;
std::vector<v8::Handle<v8::Object>> seenObjects;
int res = V8ToVPack(isolate, builder, parameter, seenHashes, seenObjects, "", false);
if (res != TRI_ERROR_NO_ERROR) {
THROW_ARANGO_EXCEPTION(res);
}
return builder;
return res;
}
// -----------------------------------------------------------------------------

View File

@ -54,8 +54,10 @@ v8::Handle<v8::Value> TRI_VPackToV8 (v8::Isolate* isolate,
/// @brief convert a V8 value to VPack value
////////////////////////////////////////////////////////////////////////////////
VPackBuilder TRI_V8ToVPack (v8::Isolate* isolate,
v8::Handle<v8::Value> const);
int TRI_V8ToVPack (v8::Isolate* isolate,
VPackBuilder& builder,
v8::Handle<v8::Value> const value,
bool keepTopLevelOpen);
#endif