1
0
Fork 0

Merge branch 'devel' into HLC

This commit is contained in:
Frank Celler 2016-07-11 07:03:49 +00:00
commit 36a9b7852e
38 changed files with 801 additions and 343 deletions

View File

@ -169,7 +169,7 @@ if (CMAKE_COMPILER_IS_GNUCC)
message(STATUS "Compiler type GNU: ${CMAKE_CXX_COMPILER}")
endif ()
# -DSNAPPY -DZLIB
if (SOLARIS)
if (SOLARIS OR DARWIN)
set(ROCKSDB_MALLOC_USABLE_SIZE "")
else()
set(ROCKSDB_MALLOC_USABLE_SIZE "-DROCKSDB_MALLOC_USABLE_SIZE")

View File

@ -1,8 +1,6 @@
devel
-----
* fixed issue #1930
* added option `--skip-lines` for arangoimp
this allows skipping the first few lines from the import file in case the
CSV or TSV import are used
@ -29,7 +27,13 @@ devel
v3.0.2 (XXXX-XX-XX)
-------------------
* don't expose local file paths in error messages.
* fixed assertion failure in case multiple remove operations were used in the same query
* fixed upsert behavior in case upsert was used in a loop with the same document example
* fixed issue #1930
* don't expose local file paths in Foxx error messages.
* fixed issue #1929

View File

@ -713,6 +713,10 @@ if (USE_OPENSSL_NO_SSL2)
add_definitions(-DOPENSSL_NO_SSL2)
endif ()
if(WIN32)
option(BUNDLE_OPENSSL "Bundle OpenSSL library" ON)
endif()
################################################################################
## V8
################################################################################

View File

@ -155,11 +155,6 @@ pack-macosx-cmake:
test -d bin || mkdir bin
rm -f ./.file-list-js
cd Build && ${MAKE}
./Installation/file-copy-js.sh . Build
cd Build && ${MAKE} install DESTDIR=${PACK_DESTDIR}
################################################################################
@ -186,11 +181,6 @@ pack-arm-cmake:
${MAKE} ${BUILT_SOURCES}
rm -f ./.file-list-js
cd Build && ${MAKE}
./Installation/file-copy-js.sh . Build
cd Build && cpack -G DEB
@ -207,11 +197,8 @@ pack-deb-cmake:
${MAKE} ${BUILT_SOURCES}
rm -f ./.file-list-js
cd Build && ${MAKE}
./Installation/file-copy-js.sh . Build
cd Build && cpack -G DEB
################################################################################
@ -255,7 +242,6 @@ pack-winXX-MOREOPTS:
${MAKE} packXX BITS="$(BITS)" TARGET="$(TARGET)" BUILD_TARGET=Debug
winXX-cmake:
rm -f ./.file-list-js
cd ../b && cmake \
-G "$(TARGET)" \
-D "CMAKE_BUILD_TYPE=RelWithDebInfo" \
@ -269,9 +255,5 @@ winXX-build:
cd ../b && cmake --build . --config $(BUILD_TARGET)
packXX:
if test ! -d ../b/js; then ./Installation/file-copy-js.sh . ../b; fi
cd ../b; rm -f ArangoDB-*.exe ArangoDB*.nsi
cd ../b && cpack -G NSIS -C $(BUILD_TARGET)
cd ../b && cpack -G NSIS64 -C $(BUILD_TARGET)
cd ../b && cpack -G ZIP -C $(BUILD_TARGET)
./Installation/Windows/installer-generator.sh $(BITS) ..\\b

View File

@ -1,25 +0,0 @@
#!/bin/bash
NSIS_PATH="/cygdrive/c/Program Files (x86)/NSIS"
#shell parameter:
#1 the bits (64 or 32)
#2 the parent directory which contains the Build64 or Build32 directory
BUILD=$2
bits=$1
# Yo windows we like year backslash paths.
WD=`pwd`
SRCPATH=`cygpath -w ${WD}|sed "s;\\\\\;\\\\\\\\\\\\\;g"`
INSTALLERNAME=`grep CPACK_PACKAGE_FILE_NAME ${BUILD}/CPackConfig.cmake | grep -o '".*"' | awk -F\" '{print $2}'`
if [ ! -f ${BUILD}/$INSTALLERNAME-internal.exe ]; then
cp ${BUILD}/$INSTALLERNAME.exe ${BUILD}/$INSTALLERNAME-internal.exe
fi
cat Installation/Windows/Templates/arango-packer-template.nsi | \
sed -e "s;@BITS@;$bits;g" \
-e "s;@INSTALLERNAME@;${INSTALLERNAME};" \
-e "s;@SRCDIR@;${SRCPATH};g" > ${BUILD}/$INSTALLERNAME.nsi
"$NSIS_PATH"/makensis.exe ${BUILD}\\$INSTALLERNAME.nsi

View File

@ -77,7 +77,6 @@ build-stamp:
# not used
rm -rf js/node/node_modules/js-yaml/demo
rm -f .file-list-js
make -j12 all
# --- end custom part for compiling

View File

@ -1,20 +0,0 @@
#!/bin/bash
set -e
SRCDIR=$1
DSTDIR=$2
${SRCDIR}/Installation/file-list-js.sh ${SRCDIR} | while read a; do
if test -f "$DSTDIR/$a"; then
echo "$DSTDIR/$a: already exists, giving up"
exit 1
fi
FROM="${SRCDIR}/$a"
TO="${DSTDIR}/$a"
DIR=`dirname "${TO}"`
chmod a+r "${FROM}"
test -d "${DIR}" || mkdir -p "${DIR}"
cp -n "${FROM}" "${TO}"
done

View File

@ -1,35 +0,0 @@
#!/bin/bash
set -e
SRCDIR=$1
if test ! -f "$SRCDIR/.file-list-js"; then
(
cd ${SRCDIR}
find \
js/actions \
js/apps/system/_admin \
js/apps/system/_api \
js/apps/system/_system \
js/client \
js/common \
js/node \
js/server \
\
-type f -print
) \
| egrep -v "^js/common/tests/" \
| egrep -v "^js/common/test-data/" \
| egrep -v "^js/client/tests/" \
| egrep -v "^js/client/test-data/" \
| egrep -v "^js/server/tests/" \
| egrep -v "^js/server/test-data/" \
| egrep -v "^js/apps/system/_admin/.*/node_modules/" \
| egrep -v "^js/apps/system/.*/test/" \
| egrep -v "^js/apps/system/.*/test_data/" \
| egrep -v "^js/apps/system/.*/coverage/" \
| egrep -v "fileset.*tests.*fixtures.*an.*odd.*filename" > "$SRCDIR/.file-list-js"
fi
cat "$SRCDIR/.file-list-js"

View File

@ -398,7 +398,9 @@ void Executor::generateCodeExpression(AstNode const* node) {
// thrown by the function
_buffer->appendText(TRI_CHAR_LENGTH_PAIR(" = function(params) { try { return _AQL.fixValue(state.f"));
_buffer->appendInteger(it.second);
_buffer->appendText(TRI_CHAR_LENGTH_PAIR(".apply(null, params)); } catch (err) { _AQL.throwFromFunction(\""));
_buffer->appendText(TRI_CHAR_LENGTH_PAIR(".apply({ name: \""));
_buffer->appendText(it.first);
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("\" }, params)); } catch (err) { _AQL.throwFromFunction(\""));
_buffer->appendText(it.first);
_buffer->appendText(TRI_CHAR_LENGTH_PAIR("\", require(\"internal\").errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR, _AQL.AQL_TO_STRING(err.stack || String(err))); } }; "));
}

View File

@ -72,6 +72,16 @@ ModificationBlock::~ModificationBlock() {}
/// @brief get some - this accumulates all input and calls the work() method
AqlItemBlock* ModificationBlock::getSome(size_t atLeast, size_t atMost) {
// for UPSERT operations, we read and write data in the same collection
// we cannot use any batching here because if the search document is not
// found, the UPSERTs INSERT operation may create it. after that, the
// search document is present and we cannot use an already queried result
// from the initial search batch
if (getPlanNode()->getType() == ExecutionNode::NodeType::UPSERT) {
atLeast = 1;
atMost = 1;
}
std::vector<AqlItemBlock*> blocks;
std::unique_ptr<AqlItemBlock> replyBlocks;

View File

@ -1545,7 +1545,7 @@ void arangodb::aql::removeUnnecessaryCalculationsRule(
// subqueries that modify data must not be optimized away
continue;
}
// will remove calculation when we get here
// will remove subquery when we get here
}
auto outvars = n->getVariablesSetHere();

View File

@ -31,10 +31,6 @@
#include "Random/RandomGenerator.h"
#include <ctime>
//XXX #warning MOP why? use ConditionVariable
#include <condition_variable>
//XXX #warning MOP why? use Mutex
#include <mutex>
#include <velocypack/Slice.h>
#include <velocypack/velocypack-aliases.h>

View File

@ -156,18 +156,18 @@ void LogfileManager::collectOptions(std::shared_ptr<ProgramOptions> options) {
options->addOption("--wal.directory", "logfile directory",
new StringParameter(&_directory));
options->addHiddenOption(
options->addOption(
"--wal.historic-logfiles",
"maximum number of historic logfiles to keep after collection",
new UInt32Parameter(&_historicLogfiles));
options->addHiddenOption(
options->addOption(
"--wal.ignore-logfile-errors",
"ignore logfile errors. this will read recoverable data from corrupted "
"logfiles but ignore any unrecoverable data",
new BooleanParameter(&_ignoreLogfileErrors));
options->addHiddenOption(
options->addOption(
"--wal.ignore-recovery-errors",
"continue recovery even if re-applying operations fails",
new BooleanParameter(&_ignoreRecoveryErrors));

View File

@ -469,13 +469,13 @@ ConsoleFeature::Prompt ConsoleFeature::buildPrompt(ClientFeature* client) {
if (c == 'E') {
// replace protocol
if (ep.find("tcp://") == 0) {
if (ep.compare(0, strlen("tcp://"), "tcp://") == 0) {
ep = ep.substr(strlen("tcp://"));
} else if (ep.find("http+tcp://") == 0) {
} else if (ep.compare(0, strlen("http+tcp://"), "http+tcp://") == 0) {
ep = ep.substr(strlen("http+tcp://"));
} else if (ep.find("ssl://") == 0) {
} else if (ep.compare(0, strlen("ssl://"), "ssl://") == 0) {
ep = ep.substr(strlen("ssl://"));
} else if (ep.find("unix://") == 0) {
} else if (ep.compare(0, strlen("unix://"), "unix://") == 0) {
ep = ep.substr(strlen("unix://"));
}
}

View File

@ -12,7 +12,9 @@ if (MSVC)
INSTALL(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT} DESTINATION bin COMPONENT Libraries)
endif()
STRING(REGEX REPLACE "\\\\" "\\\\\\\\" ETCDIR_ESCAPED "${CMAKE_INSTALL_FULL_SYSCONFDIR}")
file(TO_NATIVE_PATH "${CMAKE_INSTALL_FULL_SYSCONFDIR}" ETCDIR_NATIVE)
STRING(REGEX REPLACE "\\\\" "\\\\\\\\" ETCDIR_ESCAPED "${ETCDIR_NATIVE}")
add_definitions("-D_SYSCONFDIR_=\"${ETCDIR_ESCAPED}\"")
# database directory
@ -406,3 +408,15 @@ install(
install(
DIRECTORY ${PROJECT_BINARY_DIR}/var/lib/arangodb3-apps
DESTINATION ${CMAKE_INSTALL_FULL_LOCALSTATEDIR}/lib)
if (BUNDLE_OPENSSL)
if (NOT LIB_EAY_RELEASE_DLL OR NOT SSL_EAY_RELEASE_DLL)
message(FATAL_ERROR, "BUNDLE_OPENSSL set but couldn't locate SSL DLLs. Please set LIB_EAY_RELEASE_DLL and SSL_EAY_RELEASE_DLL")
endif()
install (FILES "${LIB_EAY_RELEASE_DLL}"
DESTINATION "${CMAKE_INSTALL_PREFIX}/bin"
COMPONENT Libraries)
install (FILES "${SSL_EAY_RELEASE_DLL}"
DESTINATION "${CMAKE_INSTALL_PREFIX}/bin"
COMPONENT Libraries)
endif()

View File

@ -64,13 +64,16 @@
"frontend/js/lib/sigma.layout.noverlap.js",
"frontend/js/lib/sigma.plugins.fullScreen.js",
"frontend/js/lib/sigma.layout.fruchtermanReingold.js",
"frontend/js/lib/sigma.exporters.svg.js",
"frontend/js/lib/worker.js",
"frontend/js/lib/supervisor.js",
// END SIGMA LIBRARIES
// START NEW
"frontend/js/lib/wheelnav.slicePath.js",
"frontend/js/lib/wheelnav.min.js",
"frontend/js/lib/raphael.min.js",
"frontend/js/lib/raphael.icons.min.js",
// END NEW LIBRARIES
"frontend/js/lib/jsoneditor-min.js",
"frontend/js/lib/strftime-min.js",
"frontend/js/lib/d3.fisheye.min.js",

View File

@ -1,28 +1,31 @@
/* global AQL_EXECUTE */
'use strict';
////////////////////////////////////////////////////////////////////////////////
/// DISCLAIMER
///
/// Copyright 2010-2013 triAGENS GmbH, Cologne, Germany
/// Copyright 2016 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 Michael Hackstein
/// @author Alan Plum
////////////////////////////////////////////////////////////////////////////////
// //////////////////////////////////////////////////////////////////////////////
// DISCLAIMER
//
// Copyright 2010-2013 triAGENS GmbH, Cologne, Germany
// Copyright 2016 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 Michael Hackstein
// @author Heiko Kernbach
// @author Alan Plum
// //////////////////////////////////////////////////////////////////////////////
const joi = require('joi');
const dd = require('dedent');
@ -42,7 +45,7 @@ API_DOCS.basePath = `/_db/${encodeURIComponent(db._name())}`;
const router = createRouter();
module.exports = router;
router.get('/config.js', function(req, res) {
router.get('/config.js', function (req, res) {
const scriptName = req.get('x-script-name');
const basePath = req.trustProxy && scriptName || '';
res.send(
@ -56,7 +59,7 @@ router.get('/config.js', function(req, res) {
})
.response(['text/javascript']);
router.get('/whoAmI', function(req, res) {
router.get('/whoAmI', function (req, res) {
res.json({user: req.arangoUser || null});
})
.summary('Return the current user')
@ -65,7 +68,6 @@ router.get('/whoAmI', function(req, res) {
Returns "false" if authentication is disabled.
`);
const authRouter = createRouter();
router.use(authRouter);
@ -78,9 +80,8 @@ authRouter.use((req, res, next) => {
next();
});
router.get('/api/*', module.context.apiDocumentation({
swaggerJson(req, res) {
swaggerJson (req, res) {
res.json(API_DOCS);
}
}))
@ -89,8 +90,7 @@ router.get('/api/*', module.context.apiDocumentation({
Mounts the system API documentation.
`);
authRouter.get('shouldCheckVersion', function(req, res) {
authRouter.get('shouldCheckVersion', function (req, res) {
const versions = notifications.versions();
res.json(Boolean(versions && versions.enableVersionNotification));
})
@ -99,8 +99,7 @@ authRouter.get('shouldCheckVersion', function(req, res) {
Check if version check is allowed.
`);
authRouter.post('disableVersionCheck', function(req, res) {
authRouter.post('disableVersionCheck', function (req, res) {
notifications.setVersions({enableVersionNotification: false});
res.json('ok');
})
@ -109,8 +108,7 @@ authRouter.post('disableVersionCheck', function(req, res) {
Disable the version check in web interface
`);
authRouter.post('/query/explain', function(req, res) {
authRouter.post('/query/explain', function (req, res) {
const bindVars = req.body.bindVars;
const query = req.body.query;
const id = req.body.id;
@ -145,8 +143,7 @@ authRouter.post('/query/explain', function(req, res) {
Explains a query in a more user-friendly way than the query_api/explain
`);
authRouter.post('/query/upload/:user', function(req, res) {
authRouter.post('/query/upload/:user', function (req, res) {
let user = req.pathParams.user;
try {
@ -187,8 +184,7 @@ authRouter.post('/query/upload/:user', function(req, res) {
This function uploads all given user queries.
`);
authRouter.get('/query/download/:user', function(req, res) {
authRouter.get('/query/download/:user', function (req, res) {
let user = req.pathParams.user;
try {
@ -210,14 +206,12 @@ authRouter.get('/query/download/:user', function(req, res) {
Download and export all queries from the given username.
`);
authRouter.get('/query/result/download/:query', function(req, res) {
authRouter.get('/query/result/download/:query', function (req, res) {
let query;
try {
query = internal.base64Decode(req.pathParams.query);
query = JSON.parse(query);
}
catch (e) {
} catch (e) {
res.throw('bad request', e.message, {cause: e});
}
@ -232,8 +226,7 @@ authRouter.get('/query/result/download/:query', function(req, res) {
This function downloads the result of a user query.
`);
authRouter.post('/graph-examples/create/:name', function(req, res) {
authRouter.post('/graph-examples/create/:name', function (req, res) {
const name = req.pathParams.name;
if (['knows_graph', 'social', 'routeplanner'].indexOf(name) === -1) {
@ -249,8 +242,7 @@ authRouter.post('/graph-examples/create/:name', function(req, res) {
Create one of the given example graphs.
`);
authRouter.post('/job', function(req, res) {
authRouter.post('/job', function (req, res) {
db._frontend.save(Object.assign(req.body, {model: 'job'}));
res.json(true);
})
@ -265,8 +257,7 @@ authRouter.post('/job', function(req, res) {
Create a new job id entry in a specific system database with a given id.
`);
authRouter.delete('/job', function(req, res) {
authRouter.delete('/job', function (req, res) {
db._frontend.removeByExample({model: 'job'}, false);
res.json(true);
})
@ -275,8 +266,7 @@ authRouter.delete('/job', function(req, res) {
Delete all jobs in a specific system database with a given id.
`);
authRouter.delete('/job/:id', function(req, res) {
authRouter.delete('/job/:id', function (req, res) {
db._frontend.removeByExample({id: req.pathParams.id}, false);
res.json(true);
})
@ -285,8 +275,7 @@ authRouter.delete('/job/:id', function(req, res) {
Delete an existing job id entry in a specific system database with a given id.
`);
authRouter.get('/job', function(req, res) {
authRouter.get('/job', function (req, res) {
const result = db._frontend.all().toArray();
res.json(result);
})
@ -295,28 +284,30 @@ authRouter.get('/job', function(req, res) {
This function returns the job ids of all currently running jobs.
`);
authRouter.get('/graph/:name', function(req, res) {
var _ = require("lodash");
authRouter.get('/graph/:name', function (req, res) {
var _ = require('lodash');
var name = req.pathParams.name;
var gm = require("@arangodb/general-graph");
//var traversal = require("@arangodb/graph/traversal");
var gm = require('@arangodb/general-graph');
// var traversal = require("@arangodb/graph/traversal");
var graph = gm._graph(name);
var vertexName = graph._vertexCollections()[0].name();
var startVertex = db[vertexName].any();
var aqlQuery =
'FOR v, e, p IN 1..3 ANY "' + startVertex._id + '" GRAPH "' + name + '"' +
var aqlQuery =
'FOR v, e, p IN 1..3 ANY "' + startVertex._id + '" GRAPH "' + name + '"' +
'RETURN p'
;
var cursor = AQL_EXECUTE(aqlQuery);
var nodesObj = {}, nodesArr = [], edgesObj = {}, edgesArr = [];
var nodesObj = {};
var nodesArr = [];
var edgesObj = {};
var edgesArr = [];
_.each(cursor.json, function(obj) {
_.each(obj.edges, function(edge) {
_.each(cursor.json, function (obj) {
_.each(obj.edges, function (edge) {
if (edge._to && edge._from) {
edgesObj[edge._from + edge._to] = {
id: edge._id,
@ -327,11 +318,10 @@ authRouter.get('/graph/:name', function(req, res) {
}
});
var label;
_.each(obj.vertices, function(node) {
_.each(obj.vertices, function (node) {
if (node.label) {
label = node.label;
}
else {
} else {
label = node._id;
}
@ -346,11 +336,11 @@ authRouter.get('/graph/:name', function(req, res) {
});
});
//array format for sigma.js
_.each(edgesObj, function(node) {
// array format for sigma.js
_.each(edgesObj, function (node) {
edgesArr.push(node);
});
_.each(nodesObj, function(node) {
_.each(nodesObj, function (node) {
nodesArr.push(node);
});
@ -358,7 +348,6 @@ authRouter.get('/graph/:name', function(req, res) {
nodes: nodesArr,
edges: edgesArr
});
})
.summary('Return vertices and edges of a graph.')
.description(dd`

File diff suppressed because one or more lines are too long

View File

@ -1041,8 +1041,10 @@ if (list.length > 0) {
</div>
</div>
<div class="pure-g pure-table pure-table-body"> <% _.each(specific, function(val, key) { %> <div class="<%= genClass %> left"><%=key%></div>
<div class="<%= genClass %> left"><%=val%></div> <% }); %> </div>
<div class="pure-g pure-table pure-table-body"> <% _.each(specific, function(val, key) { %> <div class="<%= genClass %> left"><%=val.name%></div>
<div class="<%= genClass %> left"> <% var VALUE; %> <% if (val.value) { %> <% VALUE = val.value %> <% } else { %> <% VALUE = val.default %> <% } %> <% if (val.type === 'string') { %> <input type="text" value="<%=VALUE%>" placeholder=""></input> <% } %> <% if (val.type === 'color') { %> <input type='color' name='color' value="<%=VALUE%>"/> <% } %> <% if (val.type === 'select') { %> <div class="<%= genClass %> left">
<select> <% _.each(val, function(option, optKey) { %> <% if (option.name) { %> <option> <%=option.name%> </option> <% } %> <% }); %> </select>
</div> <% } %> </div> <% }); %> </div>
</div>
@ -1063,22 +1065,37 @@ if (list.length > 0) {
</div>
</div>
<div class="pure-g pure-table pure-table-body"> <% _.each(general, function(val, key) { %> <div class="<%= genClass %> left"><%=key%></div>
<div class="<%= genClass %> left"><%=val%></div> <% }); %> </div>
<div class="pure-g pure-table pure-table-body"> <% _.each(general, function(val, key) { %> <div class="<%= genClass %> left"><%=key%></div> <% if (val.type === 'select') { %> <div class="<%= genClass %> left">
<select> <% _.each(val, function(option, optKey) { %> <% if (option.name) { %> <option> <%=option.name%> </option> <% } %> <% }); %> </select>
</div> <% } %> <% if (val.type === 'numeric') { %> <input type="text" id="<%=val %>" value="<%=val.value %>" placeholder=""></input> <% } %> <% }); %> </div>
</div>
<button id="saveGraphSettings" style="margin-top: 20px;" class="button-success pull-right">Save</button>
<button id="saveGraphSettings" style="margin-top: 20px;" class="button-success pull-right">Restore defaults</button>
</div></script><script id="graphViewer2.ejs" type="text/template"><div class="graphContent" id="graphContainer">
<div class="headerBar">
<div class="headerButtonBar" style="margin: 0;">
<ul class="headerButtonList">
<li class="enabled">
<a id="addDocument" class="headerButton">
<span title="Add new document">
<i class="fa fa-file fa-stack-1x"></i>
<i class="fa fa-plus fa-stack-1x fa-top"></i>
<a id="graph-fullscreen-btn" class="headerButton">
<span title="Switch to fullscreen mode">
<i class="fa fa-television"></i>
</span>
</a>
</li>
<li class="enabled">
<a id="downloadPNG" class="headerButton">
<span title="Download visible graph as png image">
<i class="fa fa-camera fa-stack-1x"></i>
</span>
</a>
</li>
<li class="enabled">
<a id="selectNodes" class="headerButton">
<span title="Download visible graph as png image">
<i class="fa fa-pencil fa-stack-1x"></i>
</span>
</a>
</li>
@ -1086,7 +1103,7 @@ if (list.length > 0) {
</div>
</div>
<div id="graph-fullscreen-btn"><i class="fa fa-television"></i></div>
<!--<div id="graph-fullscreen-btn"><i class="fa fa-desktop"></i></div>-->
<div id="graph-container" oncontextmenu="return false;"></div>
</div></script><script id="graphViewGroupByEntry.ejs" type="text/template"><div class="control-group">
<label for="<%=type %>_<%=id%>" class="control-label">Attribute <%=id%></label>
@ -2706,4 +2723,4 @@ var cutByResolution = function (str) {
</div>
<div id="workMonitorContent" class="innerContent">
</div></script></head><body><nav class="navbar" style="display: none"><div class="primary"><div class="navlogo"><a class="logo big" href="#"><img class="arangodbLogo" src="img/arangodb_logo_big.png"></a><a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a><a class="version"><span>VERSION: </span><span id="currentVersion"></span></a></div><div class="statmenu" id="statisticBar"></div><div class="navmenu" id="navigationBar"></div></div></nav><div id="modalPlaceholder"></div><div class="bodyWrapper" style="display: none"><div class="centralRow"><div id="navbar2" class="navbarWrapper secondary"><div class="subnavmenu" id="subNavigationBar"></div></div><div class="resizecontainer contentWrapper"><div id="loadingScreen" class="loadingScreen" style="display: none"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw margin-bottom"></i> <span class="sr-only">Loading...</span></div><div id="content" class="centralContent"></div><footer class="footer"><div id="footerBar"></div></footer></div></div></div><div id="progressPlaceholder" style="display:none"></div><div id="spotlightPlaceholder" style="display:none"></div><div id="offlinePlaceholder" style="display:none"><div class="offline-div"><div class="pure-u"><div class="pure-u-1-4"></div><div class="pure-u-1-2 offline-window"><div class="offline-header"><h3>You have been disconnected from the server</h3></div><div class="offline-body"><p>The connection to the server has been lost. The server may be under heavy load.</p><p>Trying to reconnect in <span id="offlineSeconds">10</span> seconds.</p><p class="animation_state"><span><button class="button-success">Reconnect now</button></span></p></div></div><div class="pure-u-1-4"></div></div></div></div><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="libs.js?version=1467885481708"></script><script src="app.js?version=1467885481708"></script></body></html>
</div></script></head><body><nav class="navbar" style="display: none"><div class="primary"><div class="navlogo"><a class="logo big" href="#"><img class="arangodbLogo" src="img/arangodb_logo_big.png"></a><a class="logo small" href="#"><img class="arangodbLogo" src="img/arangodb_logo_small.png"></a><a class="version"><span>VERSION: </span><span id="currentVersion"></span></a></div><div class="statmenu" id="statisticBar"></div><div class="navmenu" id="navigationBar"></div></div></nav><div id="modalPlaceholder"></div><div class="bodyWrapper" style="display: none"><div class="centralRow"><div id="navbar2" class="navbarWrapper secondary"><div class="subnavmenu" id="subNavigationBar"></div></div><div class="resizecontainer contentWrapper"><div id="loadingScreen" class="loadingScreen" style="display: none"><i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw margin-bottom"></i> <span class="sr-only">Loading...</span></div><div id="content" class="centralContent"></div><footer class="footer"><div id="footerBar"></div></footer></div></div></div><div id="progressPlaceholder" style="display:none"></div><div id="spotlightPlaceholder" style="display:none"></div><div id="offlinePlaceholder" style="display:none"><div class="offline-div"><div class="pure-u"><div class="pure-u-1-4"></div><div class="pure-u-1-2 offline-window"><div class="offline-header"><h3>You have been disconnected from the server</h3></div><div class="offline-body"><p>The connection to the server has been lost. The server may be under heavy load.</p><p>Trying to reconnect in <span id="offlineSeconds">10</span> seconds.</p><p class="animation_state"><span><button class="button-success">Reconnect now</button></span></p></div></div><div class="pure-u-1-4"></div></div></div></div><div class="arangoFrame" style=""><div class="outerDiv"><div class="innerDiv"></div></div></div><script src="libs.js?version=1467901818158"></script><script src="app.js?version=1467901818158"></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
/* jshint strict: false, unused: false */
/* global Backbone, window, arangoDocumentModel, $, arangoHelper */
window.arangoDocument = Backbone.Collection.extend({
window.ArangoDocument = Backbone.Collection.extend({
url: '/_api/document/',
model: arangoDocumentModel,
collectionInfo: {},

View File

@ -0,0 +1,248 @@
;(function(undefined) {
'use strict';
/**
* Sigma SVG Exporter
* ===================
*
* This plugin is designed to export a graph to a svg file that can be
* downloaded or just used elsewhere.
*
* Author: Guillaume Plique (Yomguithereal)
* Version: 0.0.1
*/
// Terminating if sigma were not to be found
if (typeof sigma === 'undefined')
throw 'sigma.renderers.snapshot: sigma not in scope.';
/**
* Polyfills
*/
var URL = this.URL || this.webkitURL || this;
/**
* Utilities
*/
function createBlob(data) {
return new Blob(
[data],
{type: 'image/svg+xml;charset=utf-8'}
);
}
function download(string, filename) {
if (typeof safari !== 'undefined') {
var msg = "File download does not work in Safari. Please use a modern web browser such as Firefox, Chrome, or Internet Explorer 11.";
alert(msg);
throw new Error(msg);
}
// Blob
var blob = createBlob(string),
objectUrl = window.URL.createObjectURL(blob);
if (navigator.msSaveBlob) { // IE11+ : (has Blob, but not a[download])
navigator.msSaveBlob(blob, filename);
} else if (navigator.msSaveOrOpenBlob) { // IE10+ : (has Blob, but not a[download])
navigator.msSaveOrOpenBlob(blob, filename);
} else {
// A-download
var anchor = document.createElement('a');
anchor.setAttribute('href', objectUrl);
anchor.setAttribute('download', filename);
// Firefox requires the link to be added to the DOM before it can be clicked.
document.body.appendChild(anchor);
anchor.click();
document.body.removeChild(anchor);
}
setTimeout(function() { // Firefox needs a timeout
window.URL.revokeObjectURL(objectUrl);
}, 0);
}
/**
* Defaults
*/
var DEFAULTS = {
size: '1000',
width: '1000',
height: '1000',
margin: 0.05,
classes: true,
labels: true,
data: false,
download: false,
filename: 'graph.svg'
};
var XMLNS = 'http://www.w3.org/2000/svg';
/**
* Subprocesses
*/
function optimize(svg, prefix, params) {
var nodeColorIndex = {},
edgeColorIndex = {},
count = 0,
color,
style,
styleText = '',
f,
i,
l;
// Creating style tag if needed
if (params.classes) {
style = document.createElementNS(XMLNS, 'style');
svg.insertBefore(style, svg.firstChild);
}
// Iterating over nodes
var nodes = svg.querySelectorAll('[id="' + prefix + '-group-nodes"] > [class="' + prefix + '-node"]');
for (i = 0, l = nodes.length, f = true; i < l; i++) {
color = nodes[i].getAttribute('fill');
if (!params.data)
nodes[i].removeAttribute('data-node-id');
if (params.classes) {
if (!(color in nodeColorIndex)) {
nodeColorIndex[color] = (f ? prefix + '-node' : 'c-' + (count++));
styleText += '.' + nodeColorIndex[color] + '{fill: ' + color + '}';
}
if (nodeColorIndex[color] !== prefix + '-node')
nodes[i].setAttribute('class', nodes[i].getAttribute('class') + ' ' + nodeColorIndex[color]);
nodes[i].removeAttribute('fill');
}
f = false;
}
// Iterating over edges
var edges = svg.querySelectorAll('[id="' + prefix + '-group-edges"] > [class="' + prefix + '-edge"]');
for (i = 0, l = edges.length, f = true; i < l; i++) {
color = edges[i].getAttribute('stroke');
if (!params.data)
edges[i].removeAttribute('data-edge-id');
if (params.classes) {
if (!(color in edgeColorIndex)) {
edgeColorIndex[color] = (f ? prefix + '-edge' : 'c-' + (count++));
styleText += '.' + edgeColorIndex[color] + '{stroke: ' + color + '}';
}
if (edgeColorIndex[color] !== prefix + '-edge')
edges[i].setAttribute('class', edges[i].getAttribute('class') + ' ' + edgeColorIndex[color]);
edges[i].removeAttribute('stroke');
}
f = false;
}
if (params.classes)
style.appendChild(document.createTextNode(styleText));
}
/**
* Extending prototype
*/
sigma.prototype.toSVG = function(params) {
params = params || {};
var prefix = this.settings('classPrefix'),
w = params.size || params.width || DEFAULTS.size,
h = params.size || params.height || DEFAULTS.size,
margin = params.margin || DEFAULTS.margin;
// Creating a dummy container
var container = document.createElement('div');
container.setAttribute('width', w);
container.setAttribute('height', h);
container.setAttribute('style', 'position:absolute; top: 0px; left:0px; width: ' + w + 'px; height: ' + h + 'px;');
// Add margin to deal with curved edges
var sideMargin = this.settings('sideMargin');
this.settings('sideMargin', margin);
// Fit graph to viewport
var autoRescale = this.settings('autoRescale');
this.settings('autoRescale', true);
// Creating a camera
var camera = this.addCamera();
// Creating a svg renderer
var renderer = this.addRenderer({
camera: camera,
container: container,
type: 'svg',
forceLabels: !!params.labels
});
// Refreshing
renderer.resize(w, h);
this.refresh();
// Dropping camera and renderers before something nasty happens
this.killRenderer(renderer);
this.killCamera(camera);
// reset setting
this.settings('sideMargin', sideMargin);
this.settings('autoRescale', autoRescale);
// Retrieving svg
var svg = container.querySelector('svg');
svg.removeAttribute('style');
svg.setAttribute('width', w + 'px');
svg.setAttribute('height', h + 'px');
svg.setAttribute('x', '0px');
svg.setAttribute('y', '0px');
// svg.setAttribute('viewBox', '0 0 1000 1000');
// Dropping labels
if (!params.labels) {
var labelGroup = svg.querySelector('[id="' + prefix + '-group-labels"]');
svg.removeChild(labelGroup);
}
// Dropping hovers
var hoverGroup = svg.querySelector('[id="' + prefix + '-group-hovers"]');
svg.removeChild(hoverGroup);
// Optims?
params.classes = (params.classes !== false);
if (!params.data || params.classes)
optimize(svg, prefix, params);
// Retrieving svg string
var svgString = svg.outerHTML;
// Paranoid cleanup
container = null;
// Output string
var output = '<?xml version="1.0" encoding="utf-8"?>\n';
output += '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n';
output += svgString;
if (params.download)
download(output, params.filename || DEFAULTS.filename);
return output;
};
}).call(this);

View File

@ -857,6 +857,9 @@
if (this.queryView) {
this.queryView.resize();
}
if (this.graphViewer2) {
this.graphViewer2.resize();
}
if (this.documentsView) {
this.documentsView.resize();
}

View File

@ -30,8 +30,38 @@
<div class="pure-g pure-table pure-table-body">
<% _.each(specific, function(val, key) { %>
<div class="<%= genClass %> left"><%=key%></div>
<div class="<%= genClass %> left"><%=val%></div>
<div class="<%= genClass %> left"><%=val.name%></div>
<div class="<%= genClass %> left">
<% var VALUE; %>
<% if (val.value) { %>
<% VALUE = val.value %>
<% } else { %>
<% VALUE = val.default %>
<% } %>
<% if (val.type === 'string') { %>
<input type="text" value="<%=VALUE%>" placeholder=""></input>
<% } %>
<% if (val.type === 'color') { %>
<input type='color' name='color' value="<%=VALUE%>"/>
<% } %>
<% if (val.type === 'select') { %>
<div class="<%= genClass %> left">
<select>
<% _.each(val, function(option, optKey) { %>
<% if (option.name) { %>
<option> <%=option.name%> </option>
<% } %>
<% }); %>
</select>
</div>
<% } %>
</div>
<% }); %>
</div>
@ -55,15 +85,33 @@
</div>
<div class="pure-g pure-table pure-table-body">
<% _.each(general, function(val, key) { %>
<div class="<%= genClass %> left"><%=key%></div>
<div class="<%= genClass %> left"><%=val%></div>
<% if (val.type === 'select') { %>
<div class="<%= genClass %> left">
<select>
<% _.each(val, function(option, optKey) { %>
<% if (option.name) { %>
<option> <%=option.name%> </option>
<% } %>
<% }); %>
</select>
</div>
<% } %>
<% if (val.type === 'numeric') { %>
<input type="text" id="<%=val %>" value="<%=val.value %>" placeholder=""></input>
<% } %>
<% }); %>
</div>
</div>
<button id="saveGraphSettings" style="margin-top: 20px;" class="button-success pull-right">Save</button>
<button id="saveGraphSettings" style="margin-top: 20px;" class="button-success pull-right">Restore defaults</button>
</div>
</script>

View File

@ -5,10 +5,23 @@
<div class="headerButtonBar" style="margin: 0;">
<ul class="headerButtonList">
<li class="enabled">
<a id="addDocument" class="headerButton">
<span title="Add new document">
<i class="fa fa-file fa-stack-1x"></i>
<i class="fa fa-plus fa-stack-1x fa-top"></i>
<a id="graph-fullscreen-btn" class="headerButton">
<span title="Switch to fullscreen mode">
<i class="fa fa-television"></i>
</span>
</a>
</li>
<li class="enabled">
<a id="downloadPNG" class="headerButton">
<span title="Download visible graph as png image">
<i class="fa fa-camera fa-stack-1x"></i>
</span>
</a>
</li>
<li class="enabled">
<a id="selectNodes" class="headerButton">
<span title="Download visible graph as png image">
<i class="fa fa-pencil fa-stack-1x"></i>
</span>
</a>
</li>
@ -16,7 +29,7 @@
</div>
</div>
<div id="graph-fullscreen-btn"><i class="fa fa-television"></i></div>
<!--<div id="graph-fullscreen-btn"><i class="fa fa-desktop"></i></div>-->
<div id="graph-container" oncontextmenu="return false;"></div>
</div>
</script>

View File

@ -8,14 +8,81 @@
el: '#content',
general: {
'layout': undefined,
'depth': undefined
'Layout': {
type: 'select',
noverlap: {
name: 'No overlap (fast)'
},
force: {
name: 'Force (slow)'
},
fruchtermann: {
name: 'Fruchtermann (very slow)'
}
},
'Renderer': {
type: 'select',
canvas: {
name: 'Canvas (editable)'
},
webgl: {
name: 'WebGL (only display)'
}
},
'depth': {
type: 'numeric',
value: 2
}
},
specific: {
'node_label': undefined,
'node_color': undefined,
'node_size': undefined
'nodeLabel': {
type: 'string',
name: 'Node label',
desc: 'Default node color. RGB or HEX value.',
default: '_key'
},
'nodeColor': {
type: 'color',
name: 'Node color',
desc: 'Default node color. RGB or HEX value.',
default: '#2ecc71'
},
'nodeSize': {
type: 'string',
name: 'Node size',
desc: 'Default node size. Numeric value > 0.',
value: undefined
},
'edgeLabel': {
type: 'string',
name: 'Edge label',
desc: 'Default edge label.',
value: undefined
},
'edgeColor': {
type: 'color',
name: 'Edge color',
desc: 'Default edge color. RGB or HEX value.',
default: '#cccccc'
},
'edgeSize': {
type: 'string',
name: 'Edge thickness',
desc: 'Default edge thickness. Numeric value > 0.',
value: undefined
},
'edgeType': {
type: 'select',
name: 'Edge type',
desc: 'The type of the edge',
canvas: {
name: 'Straight'
},
webgl: {
name: 'Curved'
}
}
},
template: templateEngine.createTemplate('graphSettingsView.ejs'),
@ -24,6 +91,14 @@
this.name = options.name;
},
loadGraphSettings: function () {
},
saveGraphSettings: function () {
},
events: {
},
@ -33,6 +108,9 @@
specific: this.specific
}));
arangoHelper.buildGraphSubNav(this.name, 'Settings');
// load graph settings from local storage
// apply those values to view then
}
});

View File

@ -14,6 +14,10 @@
this.initSigma();
},
events: {
'click #downloadPNG': 'downloadSVG'
},
initSigma: function () {
// init sigma
try {
@ -30,19 +34,40 @@
} catch (ignore) {}
},
downloadSVG: function () {
var self = this;
this.currentGraph.toSVG({
download: true,
filename: self.name + '.svg',
size: 1000
});
},
resize: function () {
// adjust container widht + height
$('#graph-container').width($('.centralContent').width());
$('#graph-container').height($('.centralRow').height() - 150);
},
render: function () {
this.$el.html(this.template.render({}));
arangoHelper.buildGraphSubNav(this.name, 'Content');
// adjust container widht + height
$('#graph-container').width($('.centralContent').width());
$('#graph-container').height($('.centralRow').height() - 150);
this.resize();
this.fetchGraph();
},
fetchGraph: function () {
var self = this;
$('#content').append(
'<div id="calculatingGraph" style="position: absolute; left: 25px; top: 130px;">' +
'<i class="fa fa-circle-o-notch fa-spin" style="margin-right: 10px;"></i>' +
'Calculating layout. Please wait ... </div>'
);
// TODO LOAD GRAPH SETTINGS
// var settings = this.loadGraphSettings();
$.ajax({
type: 'GET',
@ -50,6 +75,9 @@
contentType: 'application/json',
success: function (data) {
self.renderGraph(data);
},
error: function () {
$('#calculatingGraph').html('Failed to fetch graph information.');
}
});
},
@ -117,6 +145,12 @@
generateMenu(e, nodeId);
},
loadGraphSettings: function () {
var settings;
return settings;
},
editNode: function (id) {
var callback = function () {};
@ -132,35 +166,50 @@
this.Sigma = sigma;
var algorithm = 'force';
var renderer = 'webgl';
var settings = {
doubleClickEnabled: false,
minEdgeSize: 0.5,
maxEdgeSize: 4,
enableEdgeHovering: true,
// edgeHoverColor: 'edge',
// defaultEdgeHoverColor: '#000',
// defaultEdgeType: 'curve',
edgeHoverSizeRatio: 1,
edgeHoverExtremities: true
};
// adjust display settings for big graphs
if (graph.nodes.length > 500) {
// show node label if size is 20
settings.labelThreshold = 20;
}
// adjust display settings for webgl renderer
if (renderer === 'webgl') {
settings.enableEdgeHovering = false;
}
// create sigma graph
var s = new this.Sigma({
graph: graph,
container: 'graph-container',
renderer: {
container: document.getElementById('graph-container'),
type: 'canvas'
type: renderer
},
settings: {
doubleClickEnabled: false,
minEdgeSize: 0.5,
maxEdgeSize: 4,
enableEdgeHovering: true,
// edgeHoverColor: 'edge',
// defaultEdgeHoverColor: '#000',
// defaultEdgeType: 'curve',
edgeHoverSizeRatio: 1,
edgeHoverExtremities: true
}
settings: settings
});
this.currentGraph = s;
sigma.plugins.fullScreen({
container: 'graph-container',
btnId: 'graph-fullscreen-btn'
});
var renderer = 'fruchtermann';
if (renderer === 'noverlap') {
if (algorithm === 'noverlap') {
var noverlapListener = s.configNoverlap({
nodeMargin: 0.1,
scaleNodes: 1.05,
@ -175,7 +224,7 @@
if (e.type === 'interpolate') {
}
});
} else if (renderer === 'fruchtermann') {
} else if (algorithm === 'fruchtermann') {
var frListener = sigma.layouts.fruchtermanReingold.configure(s, {
iterations: 500,
easing: 'quadraticInOut',
@ -192,70 +241,60 @@
e.originalColor = e.color;
});
if (document.addEventListener) {
document.addEventListener('contextmenu', function (e) {
// my custom functionality on right click
e.preventDefault();
}, false);
} else {
document.attachEvent('oncontextmenu', function () {
// my custom functionality on right click
window.event.returnValue = false;
if (renderer !== 'webgl') {
s.bind('rightClickNode', function (e) {
var nodeId = e.data.node.id;
self.createNodeContextMenu(nodeId, e);
});
s.bind('doubleClickNode', function (e) {
var nodeId = e.data.node.id;
var toKeep = s.graph.neighbors(nodeId);
toKeep[nodeId] = e.data.node;
s.graph.nodes().forEach(function (n) {
if (toKeep[n.id]) {
n.color = n.originalColor;
} else {
n.color = '#eee';
}
});
s.graph.edges().forEach(function (e) {
if (toKeep[e.source] && toKeep[e.target]) {
e.color = 'rgb(64, 74, 83)';
} else {
e.color = '#eee';
}
});
s.refresh();
});
s.bind('doubleClickStage', function () {
s.graph.nodes().forEach(function (n) {
n.color = n.originalColor;
});
s.graph.edges().forEach(function (e) {
e.color = e.originalColor;
});
s.refresh();
});
s.bind('clickStage', function () {
self.clearOldContextMenu();
});
}
s.bind('rightClickNode', function (e) {
var nodeId = e.data.node.id;
self.createNodeContextMenu(nodeId, e);
});
s.bind('doubleClickNode', function (e) {
var nodeId = e.data.node.id;
var toKeep = s.graph.neighbors(nodeId);
toKeep[nodeId] = e.data.node;
s.graph.nodes().forEach(function (n) {
if (toKeep[n.id]) {
n.color = n.originalColor;
} else {
n.color = '#eee';
}
});
s.graph.edges().forEach(function (e) {
if (toKeep[e.source] && toKeep[e.target]) {
e.color = 'rgb(64, 74, 83)';
} else {
e.color = '#eee';
}
});
s.refresh();
});
s.bind('doubleClickStage', function () {
s.graph.nodes().forEach(function (n) {
n.color = n.originalColor;
});
s.graph.edges().forEach(function (e) {
e.color = e.originalColor;
});
s.refresh();
});
s.bind('clickStage', function () {
self.clearOldContextMenu();
});
var dragListener;
// Initialize the dragNodes plugin:
if (renderer === 'noverlap') {
if (algorithm === 'noverlap') {
s.startNoverlap();
// allow draggin nodes
dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
} else if (renderer === 'force') {
} else if (algorithm === 'force') {
s.startForceAtlas2({worker: true, barnesHutOptimize: false});
window.setTimeout(function () {
@ -263,7 +302,7 @@
dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
console.log('stopped force');
}, 3000);
} else if (renderer === 'fruchtermann') {
} else if (algorithm === 'fruchtermann') {
// Start the Fruchterman-Reingold algorithm:
sigma.layouts.fruchtermanReingold.start(s);
dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
@ -271,6 +310,8 @@
dragListener = sigma.plugins.dragNodes(s, s.renderers[0]);
}
console.log(dragListener);
$('#calculatingGraph').remove();
}
});

View File

@ -840,7 +840,7 @@ function FCALL_USER (name, parameters) {
}
try {
return FIX_VALUE(UserFunctions[prefix][name].func.apply(null, parameters));
return FIX_VALUE(UserFunctions[prefix][name].func.apply({ name: name }, parameters));
} catch (err) {
WARN(name, INTERNAL.errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR, AQL_TO_STRING(err.stack || String(err)));
return null;
@ -888,7 +888,7 @@ function FCALL_DYNAMIC (func, applyDirect, values, name, args) {
if (applyDirect) {
try {
return FIX_VALUE(toCall.apply(null, args));
return FIX_VALUE(toCall.apply({ name: name }, args));
} catch (err) {
WARN(name, INTERNAL.errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR, AQL_TO_STRING(err));
return null;
@ -902,7 +902,7 @@ function FCALL_DYNAMIC (func, applyDirect, values, name, args) {
for (i in values) {
if (values.hasOwnProperty(i)) {
args[0] = values[i];
result[i] = FIX_VALUE(toCall.apply(null, args));
result[i] = FIX_VALUE(toCall.apply({ name: name }, args));
}
}
return result;
@ -910,7 +910,7 @@ function FCALL_DYNAMIC (func, applyDirect, values, name, args) {
result = [];
for (i = 0; i < values.length; ++i) {
args[0] = values[i];
result[i] = FIX_VALUE(toCall.apply(null, args));
result[i] = FIX_VALUE(toCall.apply({ name: name }, args));
}
return result;
}

View File

@ -320,6 +320,23 @@ function ahuacatlCallUserDefinedTestSuite () {
testThrows : function () {
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR.code, "RETURN CALL('UNITTESTS::FUNC::THROWING')");
assertQueryWarningAndNull(errors.ERROR_QUERY_FUNCTION_RUNTIME_ERROR.code, "RETURN APPLY('UNITTESTS::FUNC::THROWING', [ ])");
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test function name passed from the outside
////////////////////////////////////////////////////////////////////////////////
testFunctionName : function () {
aqlfunctions.register("UnitTests::func::call", function () { return this.name; });
var actual = getQueryResults("RETURN UnitTests::func::call()");
assertEqual("UNITTESTS::FUNC::CALL", actual[0]);
actual = getQueryResults("RETURN CALL('UNITTESTS::FUNC::CALL', [])");
assertEqual("UNITTESTS::FUNC::CALL", actual[0]);
actual = getQueryResults("RETURN CALL('unittests::func::call', [])");
assertEqual("UNITTESTS::FUNC::CALL", actual[0]);
}
};

View File

@ -744,6 +744,78 @@ function ahuacatlModifySuite () {
queries.forEach(function(query) {
assertQueryError(errors.ERROR_QUERY_ACCESS_AFTER_MODIFICATION.code, query, { "@cn": cn1 }, query);
});
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test upsert on same document
////////////////////////////////////////////////////////////////////////////////
testUpsertDocumentInitiallyPresent : function () {
AQL_EXECUTE("FOR i IN 0..1999 INSERT { _key: CONCAT('test', i), value1: i } IN @@cn1", { "@cn1" : cn1 });
var expected = { writesExecuted: 1, writesIgnored: 0 };
var actual = AQL_EXECUTE("UPSERT { value1: 0 } INSERT { value1: 0, value2: 0 } UPDATE { value2: 1 } IN " + cn1, {});
assertEqual(2001, c1.count());
assertEqual(expected, sanitizeStats(actual.stats));
assertEqual([ ], actual.json);
assertEqual(0, c1.document("test0").value1);
assertEqual(1, c1.document("test0").value2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test upsert on same document
////////////////////////////////////////////////////////////////////////////////
testUpsertDocumentInitiallyNotPresent : function () {
AQL_EXECUTE("FOR i IN 0..1999 INSERT { _key: CONCAT('test', i), value1: i } IN @@cn1", { "@cn1" : cn1 });
var expected = { writesExecuted: 1, writesIgnored: 0 };
var actual = AQL_EXECUTE("UPSERT { value1: 999999 } INSERT { _key: 'test999999', value1: 999999, value2: 0 } UPDATE { value2: 1 } IN " + cn1, {});
assertEqual(2002, c1.count());
assertEqual(expected, sanitizeStats(actual.stats));
assertEqual([ ], actual.json);
assertEqual(999999, c1.document("test999999").value1);
assertEqual(0, c1.document("test999999").value2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test upsert on same document
////////////////////////////////////////////////////////////////////////////////
testUpsertDocumentRepeatedInitiallyPresent : function () {
AQL_EXECUTE("FOR i IN 0..1999 INSERT { _key: CONCAT('test', i), value1: i } IN @@cn1", { "@cn1" : cn1 });
var expected = { writesExecuted: 2000, writesIgnored: 0 };
var actual = AQL_EXECUTE("FOR i IN 1..2000 UPSERT { value1: 0 } INSERT { value1: 0, value2: 0 } UPDATE { value2: 1 } IN " + cn1, {});
assertEqual(2001, c1.count());
assertEqual(expected, sanitizeStats(actual.stats));
assertEqual([ ], actual.json);
assertEqual(0, c1.document("test0").value1);
assertEqual(1, c1.document("test0").value2);
},
////////////////////////////////////////////////////////////////////////////////
/// @brief test upsert on same document
////////////////////////////////////////////////////////////////////////////////
testUpsertDocumentRepeatedInitiallyNotPresent : function () {
AQL_EXECUTE("FOR i IN 0..1999 INSERT { _key: CONCAT('test', i), value1: i } IN @@cn1", { "@cn1" : cn1 });
var expected = { writesExecuted: 2000, writesIgnored: 0 };
var actual = AQL_EXECUTE("FOR i IN 1..2000 UPSERT { value1: 999999 } INSERT { _key: 'test999999', value1: 999999, value2: 0 } UPDATE { value2: 1 } IN " + cn1, {});
assertEqual(2002, c1.count());
assertEqual(expected, sanitizeStats(actual.stats));
assertEqual([ ], actual.json);
assertEqual(999999, c1.document("test999999").value1);
assertEqual(1, c1.document("test999999").value2);
}
};

View File

@ -546,7 +546,7 @@ void SimpleHttpClient::setRequest(
for (; i != _pathToBasicAuth.end(); ++i) {
std::string& f = i->first;
if (l->find(f) == 0) {
if (l->compare(0, f.size(), f) == 0) {
// f is prefix of l
if (f.length() > foundPrefix.length()) {
foundPrefix = f;

View File

@ -78,36 +78,34 @@ static v8::Handle<v8::Value> ObjectVPackObject(v8::Isolate* isolate,
} else {
// optimized code path for translated system attributes
VPackSlice v = VPackSlice(k.begin() + 1);
v8::Local<v8::Value> sub;
if (v.isString()) {
char const* p = v.getString(l);
sub = TRI_V8_ASCII_PAIR_STRING(p, l);
} else {
sub = TRI_VPackToV8(isolate, v, options, &slice);
}
uint8_t which = static_cast<uint8_t>(k.getUInt()) + VelocyPackHelper::AttributeBase;
switch (which) {
case VelocyPackHelper::KeyAttribute: {
char const* p = v.getString(l);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_KeyKey), TRI_V8_ASCII_PAIR_STRING(p, l));
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_KeyKey), sub);
break;
}
case VelocyPackHelper::RevAttribute: {
char const* p = v.getString(l);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_RevKey), TRI_V8_ASCII_PAIR_STRING(p, l));
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_RevKey), sub);
break;
}
case VelocyPackHelper::IdAttribute: {
if (v.isString()) {
char const* p = v.getString(l);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_IdKey), TRI_V8_ASCII_PAIR_STRING(p, l));
} else {
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_IdKey), TRI_VPackToV8(isolate, v, options, &slice));
}
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_IdKey), sub);
break;
}
case VelocyPackHelper::FromAttribute: {
char const* p = v.getString(l);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_FromKey), TRI_V8_ASCII_PAIR_STRING(p, l));
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_FromKey), sub);
break;
}
case VelocyPackHelper::ToAttribute: {
char const* p = v.getString(l);
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_ToKey), TRI_V8_ASCII_PAIR_STRING(p, l));
object->ForceSet(v8::Local<v8::String>::New(isolate, v8g->_ToKey), sub);
break;
}
}