mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel
This commit is contained in:
commit
a589bf70b6
16
CHANGELOG
16
CHANGELOG
|
@ -1,6 +1,22 @@
|
|||
v1.4
|
||||
----
|
||||
|
||||
* added "details" URL parameter for bulk import API
|
||||
|
||||
Setting the `details` URL parameter to `true` in a call to POST `/_api/import` will make
|
||||
the import return details about non-imported documents in the `details` attribute. If
|
||||
`details` is `false` or omitted, no `details` attribute will be present in the response.
|
||||
This is the same behavior that previous ArangoDB versions exposed.
|
||||
|
||||
* added "complete" option for bulk import API
|
||||
|
||||
Setting the `complete` URL parameter to `true` in a call to POST `/_api/import` will make
|
||||
the import completely fail if at least one of documents cannot be imported successfully.
|
||||
|
||||
It defaults to `false`, which will make ArangoDB continue importing the other documents
|
||||
from the import even if some documents cannot be imported. This is the same behaviour that
|
||||
previous ArangoDB versions exposed.
|
||||
|
||||
* calling `/_api/logs` (or `/_admin/logs`) is only permitted from the `_system` database now.
|
||||
|
||||
Calling this API method for/from other database will result in an HTTP 400.
|
||||
|
|
|
@ -40,6 +40,12 @@ If `complete` has a value other than `true`, valid documents will be imported wh
|
|||
invalid documents will be rejected, meaning only some of the uploaded documents
|
||||
might have been imported.
|
||||
|
||||
The `details` URL parameter can be set to `true` to make the import API return
|
||||
details about documents that could not be imported. If `details` is `true`, then
|
||||
the result will also contain a `details` attribute which is a list of detailed
|
||||
error messages. If the `details` is set to `false` or omitted, no details will be
|
||||
returned.
|
||||
|
||||
Importing Self-Contained JSON Documents {#HttpImportSelfContained}
|
||||
==================================================================
|
||||
|
||||
|
|
|
@ -107,9 +107,63 @@ Then remove the LaunchAgent
|
|||
rm ~/Library/LaunchAgents/homebrew.mxcl.arangodb.plist
|
||||
|
||||
|
||||
Apples App Store {#InstallingMacOSXAppStore}
|
||||
--------------------------------------------
|
||||
Apple's App Store {#InstallingMacOSXAppStore}
|
||||
---------------------------------------------
|
||||
|
||||
ArangoDB is available in Apple's App-Store. Please note, that it
|
||||
sometimes take a few days or weeks until the latest versions will be
|
||||
available.
|
||||
|
||||
Windows {#InstallingWindows}
|
||||
============================
|
||||
|
||||
We provide precompiled Windows binaries for ArangoDB. The binaries
|
||||
are statically linked with the required libraries such as V8, but
|
||||
they may still require some Windows platform libraries to be present.
|
||||
These libraries should be present on a Windows Vista, Windows 7, and
|
||||
Windows 8 by default, but there may be issues with other platforms.
|
||||
|
||||
The Windows builds are available as `.msi` packages
|
||||
@EXTREF{http://www.arangodb.org/download/,here}.
|
||||
Please note that we provide binaries for 32 and 64 bit Windows, and
|
||||
that you need the package that matches your platform.
|
||||
|
||||
The msi installer will install the ArangoDB server, shell (arangosh) and
|
||||
the ArangoDB import tool (arangoimp) in a directory of the user's choice.
|
||||
|
||||
Included in the distribution are some `.bat` files that can be used
|
||||
to easily start the ArangoDB server and shell. The `.bat` files will be
|
||||
installed in the same directory as ArangoDB so they should be easy to find.
|
||||
The batch files contain a lot of configuration settings, and you might want
|
||||
to eventually adjust these parameters to match your own environment.
|
||||
|
||||
To start the ArangoDB server, use the batch file `serverExample.bat`.
|
||||
It will start the ArangoDB server and will wait until you terminate it
|
||||
by pressing CTRL-C. Starting ArangoDB for the first time will automatically
|
||||
create a database sub-directory in the directory ArangoDB was installed in.
|
||||
|
||||
If you already have a previous version of ArangoDB installed and want to
|
||||
upgrade to a newer version, use the `upgradeExample.bat` file. This will
|
||||
start ArangoDB with the `--upgrade` option and perform a migration of an
|
||||
existing database.
|
||||
|
||||
To start _arangosh_, use the batch file `shellExample.bat`.
|
||||
|
||||
Please note an important limitation when running ArangoDB under Cygwin:
|
||||
Starting ArangoDB can be started from out of a Cygwin terminal, but pressing
|
||||
CTRL-C will forcefully kill the server process, without giving it a chance to
|
||||
handle the kill signal. In this case, a regular server shutdown is not
|
||||
possible, which may leave a file `LOCK` around in the server's data directory.
|
||||
This file needs to be removed manually to make ArangoDB start again.
|
||||
Additionally, as ArangoDB does not have a chance to handle the kill signal,
|
||||
the server cannot forcefully flush any data to disk on shutdown, leading to
|
||||
potential data loss.
|
||||
|
||||
Starting ArangoDB from an MS-DOS command prompt does not impose the
|
||||
limitations, and the kill signal will be handled normally by the server,
|
||||
allowing it to shut down normally.
|
||||
|
||||
Please note that when using ArangoDB's web interface with Internet Explorer
|
||||
(IE), you will need IE version 9 or higher to use all features. The web
|
||||
interface partly relies on SVG, which is not available in previous versions
|
||||
of IE.
|
||||
|
|
|
@ -8,3 +8,4 @@ TOC {#InstallingTOC}
|
|||
- @ref InstallingMacOSX
|
||||
- @ref InstallingMacOSXHomebrew
|
||||
- @ref InstallingMacOSXAppStore
|
||||
- @ref InstallingWindows
|
||||
|
|
|
@ -182,6 +182,9 @@ The web interface now provides a graph viewer on the **Graphs** tab. The graph v
|
|||
can be used to explore and navigate an existing ArangoDB graph. It supports both
|
||||
graphs in the `_graphs` system collection as well as user-defined graphs that are
|
||||
composed of an arbitrary vertex and edge collection.
|
||||
Please note that when using ArangoDB's web interface with Internet Explorer
|
||||
(IE), you will need IE version 9 or higher. The graph viewer relies on client-side
|
||||
SVG which is not available in previous versions of IE.
|
||||
|
||||
The **Dashboard** tab in the web interface provides an overview of server figures, which
|
||||
can be adjusted to user needs. New figures are polled by the web interface in a
|
||||
|
@ -410,6 +413,13 @@ Miscellaneous Improvements {#NewFeatures14Misc}
|
|||
ArangoDB 1.4 now provides a REST API to execute server-side traversals with custom
|
||||
traversal functions. The API is described @ref HttpTraversals "here".
|
||||
|
||||
The bulk import API now provides a `complete` URL parameter that can be used to
|
||||
control the behaviour when at least one document cannot be imported. Setting
|
||||
`complete` to `true` will abort the whole import and roll back any already imported
|
||||
documents. Setting it to `false` or omitting it will make the import continue
|
||||
importing documents even if some documents could not be imported. This is also the
|
||||
behaviour that previous ArangoDB versions exposed.
|
||||
|
||||
Command-Line Options added {#NewFeatures14Options}
|
||||
--------------------------------------------------
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
|
||||
#include "Basics/JsonHelper.h"
|
||||
#include "Basics/StringUtils.h"
|
||||
#include "BasicsC/string-buffer.h"
|
||||
#include "BasicsC/tri-strings.h"
|
||||
#include "Rest/HttpRequest.h"
|
||||
#include "VocBase/document-collection.h"
|
||||
|
@ -137,19 +136,24 @@ bool RestImportHandler::extractComplete () const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief log an error document
|
||||
/// @brief create a position string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestImportHandler::logDocument (TRI_json_t const* json) const {
|
||||
TRI_string_buffer_t buffer;
|
||||
std::string RestImportHandler::positionise (size_t i) const {
|
||||
return string("at position " + StringUtils::itoa(i) + ": ");
|
||||
}
|
||||
|
||||
TRI_InitStringBuffer(&buffer, TRI_UNKNOWN_MEM_ZONE);
|
||||
int res = TRI_StringifyJson(&buffer, json);
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
LOGGER_WARNING("offending document: " << buffer._buffer);
|
||||
}
|
||||
TRI_DestroyStringBuffer(&buffer);
|
||||
void RestImportHandler::registerError (RestImportResult& result,
|
||||
std::string const& errorMsg) {
|
||||
++result._numErrors;
|
||||
|
||||
result._errors.push_back(errorMsg);
|
||||
|
||||
LOGGER_WARNING(errorMsg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -158,11 +162,12 @@ void RestImportHandler::logDocument (TRI_json_t const* json) const {
|
|||
|
||||
int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
||||
TRI_json_t const* json,
|
||||
string& errorMsg,
|
||||
const bool isEdgeCollection,
|
||||
const bool waitForSync,
|
||||
const size_t i) {
|
||||
if (! TRI_IsArrayJson(json)) {
|
||||
LOGGER_WARNING("invalid JSON type (expecting array) at position " << i);
|
||||
errorMsg = positionise(i) + "invalid JSON type (expecting array)";
|
||||
|
||||
return TRI_ERROR_ARANGO_DOCUMENT_TYPE_INVALID;
|
||||
}
|
||||
|
@ -176,7 +181,7 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
const char* to = extractJsonStringValue(json, TRI_VOC_ATTRIBUTE_TO);
|
||||
|
||||
if (from == 0 || to == 0) {
|
||||
LOGGER_WARNING("missing '_from' or '_to' attribute at position " << i);
|
||||
errorMsg = positionise(i) + "missing '_from' or '_to' attribute";
|
||||
|
||||
return TRI_ERROR_ARANGO_INVALID_EDGE_ATTRIBUTE;
|
||||
}
|
||||
|
@ -211,8 +216,15 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
}
|
||||
|
||||
if (res != TRI_ERROR_NO_ERROR) {
|
||||
LOGGER_WARNING("creating document failed with error: " << TRI_errno_string(res));
|
||||
logDocument(json);
|
||||
string part = JsonHelper::toString(json);
|
||||
if (part.size() > 255) {
|
||||
// UTF-8 chars in string will be escaped so we can truncate it at any point
|
||||
part = part.substr(0, 255) + "...";
|
||||
}
|
||||
|
||||
errorMsg = positionise(i) +
|
||||
"creating document failed with error '" + TRI_errno_string(res) +
|
||||
"', offending document: " + part;
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -259,6 +271,10 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
/// occurs. Otherwise the import will continue even if some documents cannot
|
||||
/// be imported.
|
||||
///
|
||||
/// @RESTQUERYPARAM{details,boolean,optional}
|
||||
/// If set to `true` or `yes`, the result will include an attribute `details`
|
||||
/// with details about documents that could not be imported.
|
||||
///
|
||||
/// @RESTDESCRIPTION
|
||||
/// Creates documents in the collection identified by `collection-name`.
|
||||
/// The JSON representations of the documents must be passed as the body of the
|
||||
|
@ -274,6 +290,10 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
/// - `empty`: number of empty lines found in the input (will only contain a
|
||||
/// value greater zero for types `documents` or `auto`).
|
||||
///
|
||||
/// - `details`: if URL parameter `details` is set to true, the result will
|
||||
/// contain a `details` attribute which is a list with more detailed
|
||||
/// information about which documents could not be inserted.
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{201}
|
||||
|
@ -426,7 +446,7 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
///
|
||||
/// var body = [ { name: "some name" } ];
|
||||
///
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn + "&type=list", JSON.stringify(body));
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn + "&type=list&details=true", JSON.stringify(body));
|
||||
///
|
||||
/// assert(response.code === 201);
|
||||
/// var r = JSON.parse(response.body);
|
||||
|
@ -447,7 +467,7 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
///
|
||||
/// var body = '{ "_key": "abc", "value1": 25, "value2": "test" }\n{ "_key": "abc", "value1": "bar", "value2": "baz" }';
|
||||
///
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn + "&type=documents", body);
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn + "&type=documents&details=true", body);
|
||||
///
|
||||
/// assert(response.code === 201);
|
||||
/// var r = JSON.parse(response.body);
|
||||
|
@ -510,9 +530,7 @@ int RestImportHandler::handleSingleDocument (ImportTransactionType& trx,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool RestImportHandler::createFromJson (const string& type) {
|
||||
size_t numCreated = 0;
|
||||
size_t numError = 0;
|
||||
size_t numEmpty = 0;
|
||||
RestImportResult result;
|
||||
|
||||
vector<string> const& suffix = _request->suffix();
|
||||
|
||||
|
@ -621,23 +639,24 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
|
||||
StringUtils::trimInPlace(line, "\r\n\t ");
|
||||
if (line.length() == 0) {
|
||||
++numEmpty;
|
||||
++result._numEmpty;
|
||||
continue;
|
||||
}
|
||||
|
||||
TRI_json_t* json = parseJsonLine(line);
|
||||
|
||||
res = handleSingleDocument(trx, json, isEdgeCollection, waitForSync, i);
|
||||
string errorMsg;
|
||||
res = handleSingleDocument(trx, json, errorMsg, isEdgeCollection, waitForSync, i);
|
||||
|
||||
if (json != 0) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
++numCreated;
|
||||
++result._numCreated;
|
||||
}
|
||||
else {
|
||||
++numError;
|
||||
registerError(result, errorMsg);
|
||||
|
||||
if (complete) {
|
||||
// only perform a full import: abort
|
||||
|
@ -669,13 +688,14 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
for (size_t i = 0; i < n; ++i) {
|
||||
TRI_json_t const* json = (TRI_json_t const*) TRI_AtVector(&documents->_value._objects, i);
|
||||
|
||||
res = handleSingleDocument(trx, json, isEdgeCollection, waitForSync, i + 1);
|
||||
string errorMsg;
|
||||
res = handleSingleDocument(trx, json, errorMsg, isEdgeCollection, waitForSync, i + 1);
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
++numCreated;
|
||||
++result._numCreated;
|
||||
}
|
||||
else {
|
||||
++numError;
|
||||
registerError(result, errorMsg);
|
||||
|
||||
if (complete) {
|
||||
// only perform a full import: abort
|
||||
|
@ -703,7 +723,7 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
}
|
||||
else {
|
||||
// generate result
|
||||
generateDocumentsCreated(numCreated, numError, numEmpty);
|
||||
generateDocumentsCreated(result);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -737,6 +757,10 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
/// occurs. Otherwise the import will continue even if some documents cannot
|
||||
/// be imported.
|
||||
///
|
||||
/// @RESTQUERYPARAM{details,boolean,optional}
|
||||
/// If set to `true` or `yes`, the result will include an attribute `details`
|
||||
/// with details about documents that could not be imported.
|
||||
///
|
||||
/// @RESTDESCRIPTION
|
||||
/// Creates documents in the collection identified by `collection-name`.
|
||||
/// The first line of the request body must contain a JSON-encoded list of
|
||||
|
@ -754,6 +778,10 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
/// - `empty`: number of empty lines found in the input (will only contain a
|
||||
/// value greater zero for types `documents` or `auto`).
|
||||
///
|
||||
/// - `details`: if URL parameter `details` is set to true, the result will
|
||||
/// contain a `details` attribute which is a list with more detailed
|
||||
/// information about which documents could not be inserted.
|
||||
///
|
||||
/// @RESTRETURNCODES
|
||||
///
|
||||
/// @RESTRETURNCODE{201}
|
||||
|
@ -854,7 +882,7 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
///
|
||||
/// var body = '[ "name" ]\n[ "some name" ]\n[ "other name" ]';
|
||||
///
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn, body);
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn + "&details=true", body);
|
||||
///
|
||||
/// assert(response.code === 201);
|
||||
/// var r = JSON.parse(response.body)
|
||||
|
@ -875,7 +903,7 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
///
|
||||
/// var body = '[ "_key", "value1", "value2" ]\n[ "abc", 25, "test" ]\n[ "abc", "bar", "baz" ]';
|
||||
///
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn, body);
|
||||
/// var response = logCurlRequestRaw('POST', "/_api/import?collection=" + cn + "&details=true", body);
|
||||
///
|
||||
/// assert(response.code === 201);
|
||||
/// var r = JSON.parse(response.body)
|
||||
|
@ -938,9 +966,7 @@ bool RestImportHandler::createFromJson (const string& type) {
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool RestImportHandler::createFromKeyValueList () {
|
||||
size_t numCreated = 0;
|
||||
size_t numError = 0;
|
||||
size_t numEmpty = 0;
|
||||
RestImportResult result;
|
||||
|
||||
vector<string> const& suffix = _request->suffix();
|
||||
|
||||
|
@ -997,25 +1023,15 @@ bool RestImportHandler::createFromKeyValueList () {
|
|||
keys = parseJsonLine(line);
|
||||
}
|
||||
|
||||
if (keys == 0 || keys->_type != TRI_JSON_LIST) {
|
||||
if (keys != 0) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys);
|
||||
}
|
||||
|
||||
LOGGER_WARNING("no JSON string list found first line");
|
||||
generateError(HttpResponse::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"no JSON string list found in first line");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! checkKeys(keys)) {
|
||||
LOGGER_WARNING("no JSON string list in first line found");
|
||||
generateError(HttpResponse::BAD,
|
||||
TRI_ERROR_HTTP_BAD_PARAMETER,
|
||||
"no JSON string list in first line found");
|
||||
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys);
|
||||
if (keys != 0) {
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, keys);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1063,7 +1079,7 @@ bool RestImportHandler::createFromKeyValueList () {
|
|||
|
||||
StringUtils::trimInPlace(line, "\r\n\t ");
|
||||
if (line.length() == 0) {
|
||||
++numEmpty;
|
||||
++result._numEmpty;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1071,20 +1087,25 @@ bool RestImportHandler::createFromKeyValueList () {
|
|||
|
||||
if (values != 0) {
|
||||
// build the json object from the list
|
||||
TRI_json_t* json = createJsonObject(keys, values, line);
|
||||
string errorMsg;
|
||||
|
||||
TRI_json_t* json = createJsonObject(keys, values, errorMsg, line, i);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, values);
|
||||
|
||||
res = handleSingleDocument(trx, json, isEdgeCollection, waitForSync, i);
|
||||
|
||||
|
||||
if (json != 0) {
|
||||
res = handleSingleDocument(trx, json, errorMsg, isEdgeCollection, waitForSync, i);
|
||||
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, json);
|
||||
}
|
||||
else {
|
||||
// raise any error
|
||||
res = TRI_ERROR_INTERNAL;
|
||||
}
|
||||
|
||||
if (res == TRI_ERROR_NO_ERROR) {
|
||||
++numCreated;
|
||||
++result._numCreated;
|
||||
}
|
||||
else {
|
||||
++numError;
|
||||
registerError(result, errorMsg);
|
||||
|
||||
if (complete) {
|
||||
// only perform a full import: abort
|
||||
|
@ -1096,8 +1117,8 @@ bool RestImportHandler::createFromKeyValueList () {
|
|||
}
|
||||
}
|
||||
else {
|
||||
LOGGER_WARNING("no valid JSON data in line: " << line);
|
||||
++numError;
|
||||
string errorMsg = positionise(i) + "no valid JSON data";
|
||||
registerError(result, errorMsg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1115,7 +1136,7 @@ bool RestImportHandler::createFromKeyValueList () {
|
|||
}
|
||||
else {
|
||||
// generate result
|
||||
generateDocumentsCreated(numCreated, numError, numEmpty);
|
||||
generateDocumentsCreated(result);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1125,18 +1146,34 @@ bool RestImportHandler::createFromKeyValueList () {
|
|||
/// @brief create response for number of documents created / failed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestImportHandler::generateDocumentsCreated (size_t numCreated, size_t numError, size_t numEmpty) {
|
||||
void RestImportHandler::generateDocumentsCreated (RestImportResult const& result) {
|
||||
_response = createResponse(HttpResponse::CREATED);
|
||||
_response->setContentType("application/json; charset=utf-8");
|
||||
|
||||
TRI_json_t json;
|
||||
|
||||
TRI_InitArrayJson(TRI_CORE_MEM_ZONE, &json);
|
||||
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "error", TRI_CreateBooleanJson(TRI_CORE_MEM_ZONE, false));
|
||||
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "created", TRI_CreateNumberJson(TRI_CORE_MEM_ZONE, (double) result._numCreated));
|
||||
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "errors", TRI_CreateNumberJson(TRI_CORE_MEM_ZONE, (double) result._numErrors));
|
||||
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "empty", TRI_CreateNumberJson(TRI_CORE_MEM_ZONE, (double) result._numEmpty));
|
||||
|
||||
_response->body()
|
||||
.appendText("{\"error\":false,\"created\":")
|
||||
.appendInteger(numCreated)
|
||||
.appendText(",\"errors\":")
|
||||
.appendInteger(numError)
|
||||
.appendText(",\"empty\":")
|
||||
.appendInteger(numEmpty)
|
||||
.appendText("}");
|
||||
bool found;
|
||||
char const* detailsStr = _request->value("details", found);
|
||||
|
||||
// include failure details?
|
||||
if (found && StringUtils::boolean(detailsStr)) {
|
||||
TRI_json_t* messages = TRI_CreateListJson(TRI_CORE_MEM_ZONE);
|
||||
|
||||
for (size_t i = 0, n = result._errors.size(); i < n; ++i) {
|
||||
const string& msg = result._errors[i];
|
||||
TRI_PushBack3ListJson(TRI_CORE_MEM_ZONE, messages, TRI_CreateString2CopyJson(TRI_CORE_MEM_ZONE, msg.c_str(), msg.size()));
|
||||
}
|
||||
TRI_Insert3ArrayJson(TRI_CORE_MEM_ZONE, &json, "details", messages);
|
||||
}
|
||||
|
||||
generateResult(HttpResponse::CREATED, &json);
|
||||
TRI_DestroyJson(TRI_CORE_MEM_ZONE, &json);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1160,21 +1197,24 @@ TRI_json_t* RestImportHandler::parseJsonLine (const string& line) {
|
|||
|
||||
TRI_json_t* RestImportHandler::createJsonObject (const TRI_json_t* keys,
|
||||
const TRI_json_t* values,
|
||||
const string& line) {
|
||||
string& errorMsg,
|
||||
const string& line,
|
||||
const size_t lineNumber) {
|
||||
|
||||
if (values->_type != TRI_JSON_LIST) {
|
||||
LOGGER_WARNING("no valid JSON list data in line: " << line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (keys->_value._objects._length != values->_value._objects._length) {
|
||||
LOGGER_WARNING("wrong number of JSON values in line: " << line);
|
||||
errorMsg = positionise(lineNumber) + "no valid JSON list data";
|
||||
return 0;
|
||||
}
|
||||
|
||||
const size_t n = keys->_value._objects._length;
|
||||
|
||||
if (n != values->_value._objects._length) {
|
||||
errorMsg = positionise(lineNumber) + "wrong number of JSON values";
|
||||
return 0;
|
||||
}
|
||||
|
||||
TRI_json_t* result = TRI_CreateArray2Json(TRI_UNKNOWN_MEM_ZONE, n);
|
||||
|
||||
if (result == 0) {
|
||||
LOGGER_ERROR("out of memory");
|
||||
return 0;
|
||||
|
@ -1197,8 +1237,8 @@ TRI_json_t* RestImportHandler::createJsonObject (const TRI_json_t* keys,
|
|||
/// @brief validate keys
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool RestImportHandler::checkKeys (TRI_json_t* keys) {
|
||||
if (keys->_type != TRI_JSON_LIST) {
|
||||
bool RestImportHandler::checkKeys (TRI_json_t const* keys) {
|
||||
if (! TRI_IsListJson(keys)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -61,6 +61,29 @@
|
|||
namespace triagens {
|
||||
namespace arango {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- RestImportResult
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
struct RestImportResult {
|
||||
|
||||
public:
|
||||
RestImportResult () :
|
||||
_numErrors(0),
|
||||
_numEmpty(0),
|
||||
_numCreated(0),
|
||||
_errors() {
|
||||
}
|
||||
|
||||
~RestImportResult () { }
|
||||
|
||||
size_t _numErrors;
|
||||
size_t _numEmpty;
|
||||
size_t _numCreated;
|
||||
|
||||
std::vector<std::string> _errors;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief import request handler
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -131,10 +154,17 @@ namespace triagens {
|
|||
bool extractComplete () const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief log an error document
|
||||
/// @brief create a position string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void logDocument (TRI_json_t const*) const;
|
||||
std::string positionise (size_t) const;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief register an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void registerError (RestImportResult&,
|
||||
std::string const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief process a single JSON document
|
||||
|
@ -142,6 +172,7 @@ namespace triagens {
|
|||
|
||||
int handleSingleDocument (ImportTransactionType&,
|
||||
TRI_json_t const*,
|
||||
std::string&,
|
||||
const bool,
|
||||
const bool,
|
||||
const size_t);
|
||||
|
@ -170,13 +201,13 @@ namespace triagens {
|
|||
/// @brief creates the result
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void generateDocumentsCreated (size_t, size_t, size_t);
|
||||
void generateDocumentsCreated (RestImportResult const&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief parses a string
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TRI_json_t* parseJsonLine (const string&);
|
||||
TRI_json_t* parseJsonLine (const std::string&);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief builds a TRI_json_t object from a key and value list
|
||||
|
@ -184,13 +215,15 @@ namespace triagens {
|
|||
|
||||
TRI_json_t* createJsonObject (const TRI_json_t*,
|
||||
const TRI_json_t*,
|
||||
const string&);
|
||||
std::string&,
|
||||
const std::string&,
|
||||
const size_t);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief checks the keys, returns true if all values in the list are strings.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool checkKeys (TRI_json_t*);
|
||||
bool checkKeys (TRI_json_t const*);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
|
@ -80,20 +80,21 @@
|
|||
.footer-left {
|
||||
background: none repeat scroll 0 0 #333232;
|
||||
color: #FFFFFF;
|
||||
width: 33.3%;
|
||||
width: 45%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.footer-mid {
|
||||
background: none repeat scroll 0 0 #333232;
|
||||
color: #FFFFFF;
|
||||
width: 33.3%;
|
||||
width: 45%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.footer-right {
|
||||
background: none repeat scroll 0 0 #333232;
|
||||
color: #333232;
|
||||
width: 45%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
|
||||
<div class="footer-left">
|
||||
<p> <a id="currentUser" style="color:#FFFFFF"></a></p>
|
||||
</div>
|
||||
|
||||
<div class="copy footer-mid">
|
||||
<!--p> <a id="currentUser" style="color:#FFFFFF"></a></p-->
|
||||
<p>Copyright (c) triAGENS GmbH | <a href="#about">About</a></p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ gs = _.sortBy(gs, sortF);
|
|||
<div class="control-group">
|
||||
<label for="randomStart" class="control-label">Display random vertex at start</label>
|
||||
<div class="controls">
|
||||
<input id="randomStart" type="checkbox" name="randomStart" class="input-xlarge">
|
||||
<input id="randomStart" type="checkbox" name="randomStart" class="input-xlarge" checked>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ var footerView = Backbone.View.extend({
|
|||
$('.logs-menu').css('visibility', 'hidden');
|
||||
$('.logs-menu').css('display', 'none');
|
||||
}
|
||||
self.renderVersion();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -61,12 +61,28 @@ window.graphView = Backbone.View.extend({
|
|||
width,
|
||||
self = this;
|
||||
|
||||
ecol = $("#edgeCollection").val();
|
||||
ncol = $("#nodeCollection").val();
|
||||
undirected = !!$("#undirected").attr("checked");
|
||||
label = $("#nodeLabel").val();
|
||||
color = $("#nodeColor").val();
|
||||
randomStart = !!$("#randomStart").attr("checked");
|
||||
|
||||
var selected = $("input[type='radio'][name='loadtype']:checked").attr("id");
|
||||
if (selected === "collections") {
|
||||
// selected two individual collections
|
||||
ecol = $("#edgeCollection").val();
|
||||
ncol = $("#nodeCollection").val();
|
||||
}
|
||||
else {
|
||||
// selected a "graph"
|
||||
var graphName = $("#graph").val(),
|
||||
graph = _.find(this.graphs, function(g) { return g._key === graphName; });
|
||||
|
||||
if (graph) {
|
||||
ecol = graph.edges;
|
||||
ncol = graph.vertices;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
groupByAttribute = [];
|
||||
$("#group_by_list input").each(function() {
|
||||
|
@ -103,6 +119,7 @@ window.graphView = Backbone.View.extend({
|
|||
};
|
||||
}
|
||||
width = this.width || $("#content").width();
|
||||
|
||||
$("#background").remove();
|
||||
if (randomStart) {
|
||||
$.ajax({
|
||||
|
@ -119,7 +136,7 @@ window.graphView = Backbone.View.extend({
|
|||
width,
|
||||
680,
|
||||
config,
|
||||
data.document._id);
|
||||
(data.document && data.document._id));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -142,8 +159,11 @@ window.graphView = Backbone.View.extend({
|
|||
url: "/_api/graph",
|
||||
contentType: "application/json",
|
||||
success: function(data) {
|
||||
self.graphs = _.pluck(data.graphs, "_key");
|
||||
$(self.el).html(self.template.render({col: self.collection, gs: self.graphs}));
|
||||
self.graphs = data.graphs;
|
||||
$(self.el).html(self.template.render({
|
||||
col: self.collection,
|
||||
gs: _.pluck(self.graphs, "_key")
|
||||
}));
|
||||
delete self.ui;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -91,8 +91,17 @@ void RestBaseHandler::handleError (TriagensError const& error) {
|
|||
/// @brief generates a result from JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestBaseHandler::generateResult (TRI_json_t* json) {
|
||||
_response = createResponse(HttpResponse::OK);
|
||||
void RestBaseHandler::generateResult (TRI_json_t const* json) {
|
||||
generateResult(HttpResponse::OK, json);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generates a result from JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestBaseHandler::generateResult (HttpResponse::HttpResponseCode code,
|
||||
TRI_json_t const* json) {
|
||||
_response = createResponse(code);
|
||||
_response->setContentType("application/json; charset=utf-8");
|
||||
|
||||
int res = TRI_StringifyJson(_response->body().stringBuffer(), json);
|
||||
|
@ -108,7 +117,8 @@ void RestBaseHandler::generateResult (TRI_json_t* json) {
|
|||
/// @brief generates an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RestBaseHandler::generateError (HttpResponse::HttpResponseCode code, int errorCode) {
|
||||
void RestBaseHandler::generateError (HttpResponse::HttpResponseCode code,
|
||||
int errorCode) {
|
||||
char const* message = TRI_errno_string(errorCode);
|
||||
|
||||
if (message) {
|
||||
|
|
|
@ -112,22 +112,29 @@ namespace triagens {
|
|||
/// @brief generates a result from JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void generateResult (TRI_json_t* json);
|
||||
virtual void generateResult (TRI_json_t const* json);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generates a result from JSON
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void generateResult (rest::HttpResponse::HttpResponseCode,
|
||||
TRI_json_t const*);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generates an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void generateError (rest::HttpResponse::HttpResponseCode,
|
||||
int errorCode);
|
||||
int);
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief generates an error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual void generateError (rest::HttpResponse::HttpResponseCode,
|
||||
int errorCode,
|
||||
string const& details);
|
||||
int,
|
||||
string const&);
|
||||
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue