1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into mjmh

Conflicts:
	arangod/RestServer/ArangoServer.cpp
	arangod/RestServer/ArangoServer.h
	arangod/VocBase/server.cpp
	js/common/bootstrap/errors.js
This commit is contained in:
Jan Steemann 2014-06-13 02:23:03 +02:00
commit d5e695e63f
32 changed files with 7404 additions and 174 deletions

View File

@ -1,6 +1,8 @@
v2.2.0 (XXXX-XX-XX)
-------------------
* fixed check-version for empty directory
* moved try/catch block to the top of routing chain
* added mountedApp function for foxx-manager

File diff suppressed because it is too large Load Diff

View File

@ -146,6 +146,7 @@ attributes are required though):
* *license*: Short form of the license (MIT, GPL...)
* *name*: Name of the application (Meta information)
* *repository*: An object with information about where you can find the repository: *type* and *url*
* *rootElement*: Do you want to have a root element in the requests bodies? Default is false.
* *setup*: Path to a setup script
* *teardown*: Path to a teardown script
* *thumbnail*: Path to a thumbnail that represents the application (Meta information)
@ -528,4 +529,4 @@ When the TemplateMiddleware is included, you will have access to the render func
### Render
@copydetails JSF_foxx_TemplateMiddleware_response_render
-->
-->

View File

@ -78,7 +78,23 @@ alternative call:
_key: "123"
};
```
!SUBSECTION Orphan Collections
Each graph has an orphan collection. It consists of arbitrary many vertex collection (type *document*), that are not
used in an edge definition of the graph. If the graph is extended with an edge definition, which is part of the orphan
collection, it will be removed from the orphan collection automatically.
!SUBSUBSECTION Add
<!-- @startDocuBlock JSF_general_graph__addOrphanCollection -->
!SUBSUBSECTION Read
<!-- @startDocuBlock JSF_general_graph__getOrphanCollections -->
!SUBSUBSECTION Remove
<!-- @startDocuBlock JSF_general_graph__removeOrphanCollection -->
!SUBSECTION Read a graph

View File

@ -39,11 +39,11 @@ start () {
fi
if [ "$1" = "--upgrade" ]; then
$DAEMON -c $CONF --uid arangodb --gid arangodb $@
$DAEMON -c $CONF --uid arangodb --gid arangodb --no-server $@
RETVAL=$?
log_end_msg $RETVAL
else
$DAEMON -c $CONF --uid arangodb --gid arangodb --check-version
$DAEMON -c $CONF --uid arangodb --gid arangodb --no-server --check-version
RETVAL=$?
if test $RETVAL -eq 0; then

View File

@ -721,6 +721,27 @@ int ArangoServer::startupServer () {
if (_applicationServer->programOptions().has("no-server")) {
startServer = false;
}
// check version
bool checkVersion = false;
if (_applicationServer->programOptions().has("check-version")) {
checkVersion = true;
}
// run upgrade script
bool performUpgrade = false;
if (_applicationServer->programOptions().has("upgrade")) {
performUpgrade = true;
}
// skip an upgrade even if VERSION is missing
bool skipUpgrade = false;
if (_applicationServer->programOptions().has("no-upgrade")) {
skipUpgrade = true;
}
// special treatment for the write-ahead log
// the log must exist before all other server operations can start
@ -747,7 +768,7 @@ int ArangoServer::startupServer () {
LOG_WARNING("no shutdown info found. scanning datafiles for last tick...");
}
openDatabases(iterateMarkersOnOpen);
openDatabases(checkVersion, performUpgrade, iterateMarkersOnOpen);
if (! wal::LogfileManager::instance()->open()) {
LOG_FATAL_AND_EXIT("Unable to finish WAL recovery procedure");
@ -781,18 +802,6 @@ int ArangoServer::startupServer () {
_applicationV8->setVocbase(vocbase);
_applicationV8->setConcurrency(concurrency);
bool performUpgrade = false;
if (_applicationServer->programOptions().has("upgrade")) {
performUpgrade = true;
}
// skip an upgrade even if VERSION is missing
bool skipUpgrade = false;
if (_applicationServer->programOptions().has("no-upgrade")) {
skipUpgrade = true;
}
// .............................................................................
// prepare everything
@ -818,7 +827,7 @@ int ArangoServer::startupServer () {
_applicationServer->prepare2();
// run version check
if (_applicationServer->programOptions().has("check-version")) {
if (checkVersion) {
_applicationV8->runUpgradeCheck();
}
@ -1065,7 +1074,9 @@ int ArangoServer::runScript (TRI_vocbase_t* vocbase) {
/// @brief opens all databases
////////////////////////////////////////////////////////////////////////////////
void ArangoServer::openDatabases (bool iterateMarkersOnOpen) {
void ArangoServer::openDatabases (bool checkVersion,
bool performUpgrade,
bool iterateMarkersOnOpen) {
TRI_vocbase_defaults_t defaults;
// override with command-line options
@ -1093,10 +1104,13 @@ void ArangoServer::openDatabases (bool iterateMarkersOnOpen) {
LOG_FATAL_AND_EXIT("cannot create server instance: out of memory");
}
bool const isUpgrade = _applicationServer->programOptions().has("upgrade");
res = TRI_StartServer(_server, isUpgrade);
res = TRI_StartServer(_server, checkVersion, performUpgrade);
if (res != TRI_ERROR_NO_ERROR) {
if (checkVersion && res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
TRI_EXIT_FUNCTION(EXIT_SUCCESS, NULL);
}
LOG_FATAL_AND_EXIT("cannot start server: %s", TRI_errno_string(res));
}

View File

@ -154,7 +154,9 @@ namespace triagens {
/// @brief opens all system databases
////////////////////////////////////////////////////////////////////////////////
void openDatabases (bool);
void openDatabases (bool,
bool,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief closes all database

View File

@ -300,12 +300,16 @@ static int WriteServerId (char const* filename) {
/// @brief read / create the server id on startup
////////////////////////////////////////////////////////////////////////////////
static int DetermineServerId (TRI_server_t* server) {
static int DetermineServerId (TRI_server_t* server, bool checkVersion) {
int res;
res = ReadServerId(server->_serverIdFilename);
if (res == TRI_ERROR_FILE_NOT_FOUND) {
if (checkVersion) {
return TRI_ERROR_ARANGO_EMPTY_DATADIR;
}
// id file does not yet exist. now create it
res = GenerateServerId();
@ -1274,7 +1278,8 @@ static int Move14AlphaDatabases (TRI_server_t* server) {
////////////////////////////////////////////////////////////////////////////////
static int InitDatabases (TRI_server_t* server,
bool isUpgrade) {
bool checkVersion,
bool performUpgrade) {
TRI_ASSERT(server != nullptr);
@ -1287,7 +1292,7 @@ static int InitDatabases (TRI_server_t* server,
if (names._length == 0) {
char* name;
if (! isUpgrade && HasOldCollections(server)) {
if (! performUpgrade && HasOldCollections(server)) {
LOG_ERROR("no databases found. Please start the server with the --upgrade option");
return TRI_ERROR_ARANGO_DATADIR_INVALID;
@ -1305,7 +1310,7 @@ static int InitDatabases (TRI_server_t* server,
}
}
if (res == TRI_ERROR_NO_ERROR && isUpgrade) {
if (res == TRI_ERROR_NO_ERROR && performUpgrade) {
char const* systemName;
TRI_ASSERT(names._length > 0);
@ -1649,7 +1654,10 @@ TRI_server_id_t TRI_GetIdServer () {
////////////////////////////////////////////////////////////////////////////////
int TRI_StartServer (TRI_server_t* server,
bool isUpgrade) {
bool checkVersion,
bool performUpgrade) {
int res;
if (! TRI_IsDirectory(server->_basePath)) {
LOG_ERROR("database path '%s' is not a directory",
server->_basePath);
@ -1669,7 +1677,7 @@ int TRI_StartServer (TRI_server_t* server,
// check that the database is not locked and lock it
// .............................................................................
int res = TRI_VerifyLockFile(server->_lockFilename);
res = TRI_VerifyLockFile(server->_lockFilename);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("database is locked, please check the lock file '%s'",
@ -1696,7 +1704,11 @@ int TRI_StartServer (TRI_server_t* server,
// read the server id
// .............................................................................
res = DetermineServerId(server);
res = DetermineServerId(server, checkVersion);
if (res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
return res;
}
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("reading/creating server file failed: %s",
@ -1733,7 +1745,11 @@ int TRI_StartServer (TRI_server_t* server,
// perform an eventual migration of the databases.
// .............................................................................
res = InitDatabases(server, isUpgrade);
res = InitDatabases(server, checkVersion, performUpgrade);
if (res == TRI_ERROR_ARANGO_EMPTY_DATADIR) {
return res;
}
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("unable to initialise databases: %s",
@ -1748,7 +1764,7 @@ int TRI_StartServer (TRI_server_t* server,
if (server->_appPath != nullptr &&
strlen(server->_appPath) > 0 &&
! TRI_IsDirectory(server->_appPath)) {
if (! isUpgrade) {
if (! performUpgrade) {
LOG_ERROR("specified --javascript.app-path directory '%s' does not exist. "
"Please start again with --upgrade option to create it.",
server->_appPath);
@ -1768,7 +1784,7 @@ int TRI_StartServer (TRI_server_t* server,
if (server->_devAppPath != nullptr &&
strlen(server->_devAppPath) > 0 &&
! TRI_IsDirectory(server->_devAppPath)) {
if (! isUpgrade) {
if (! performUpgrade) {
LOG_ERROR("specified --javascript.dev-app-path directory '%s' does not exist. "
"Please start again with --upgrade option to create it.",
server->_devAppPath);
@ -1818,7 +1834,7 @@ int TRI_StartServer (TRI_server_t* server,
// .............................................................................
// scan all databases
res = OpenDatabases(server, isUpgrade);
res = OpenDatabases(server, performUpgrade);
if (res != TRI_ERROR_NO_ERROR) {
LOG_ERROR("could not iterate over all databases: %s",
@ -2500,6 +2516,10 @@ bool TRI_MSync (int fd,
return true;
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}"

View File

@ -144,7 +144,8 @@ TRI_server_id_t TRI_GetIdServer (void);
////////////////////////////////////////////////////////////////////////////////
int TRI_StartServer (TRI_server_t*,
bool);
bool checkVersion,
bool performUpgrade);
////////////////////////////////////////////////////////////////////////////////
/// @brief stop the server

View File

@ -15,7 +15,9 @@ JAVASCRIPT_BROWSER = \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-query-cursor.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-statement.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph-blueprint.js \
js/apps/system/aardvark/frontend/js/modules/org/arangodb/simple-query.js \
\
js/apps/system/aardvark/frontend/js/modules/org/arangodb-common.js \
@ -31,6 +33,7 @@ JAVASCRIPT_BROWSER = \
js/apps/system/aardvark/frontend/js/bootstrap/errors.js \
js/apps/system/aardvark/frontend/js/bootstrap/monkeypatches.js \
js/apps/system/aardvark/frontend/js/bootstrap/module-internal.js \
js/apps/system/aardvark/frontend/js/bootstrap/module-console.js \
\
js/apps/system/aardvark/frontend/js/client/client.js \
js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js

View File

@ -104,6 +104,7 @@
"ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING" : { "code" : 1234, "message" : "index insertion warning - attribute missing in document" },
"ERROR_ARANGO_INDEX_CREATION_FAILED" : { "code" : 1235, "message" : "index creation failed" },
"ERROR_ARANGO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" },
"ERROR_ARANGO_EMPTY_DATADIR" : { "code" : 1301, "message" : "server database directory is empty" },
"ERROR_REPLICATION_NO_RESPONSE" : { "code" : 1400, "message" : "no response" },
"ERROR_REPLICATION_INVALID_RESPONSE" : { "code" : 1401, "message" : "invalid response" },
"ERROR_REPLICATION_MASTER_ERROR" : { "code" : 1402, "message" : "master error" },
@ -206,13 +207,17 @@
"ERROR_GRAPH_COULD_NOT_CHANGE_EDGE" : { "code" : 1908, "message" : "could not change edge" },
"ERROR_GRAPH_TOO_MANY_ITERATIONS" : { "code" : 1909, "message" : "too many iterations" },
"ERROR_GRAPH_INVALID_FILTER_RESULT" : { "code" : 1910, "message" : "invalid filter result" },
"ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "an edge collection may only be used once in one edge definition of a graph." },
"ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : " is already used by another graph in a different edge definition." },
"ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "a graph name is required to create a graph." },
"ERROR_GRAPH_CREATE_MISSING_EDGE_DEFINITION" : { "code" : 1923, "message" : "at least one edge definition is required to create a graph." },
"ERROR_GRAPH_EDGE_COLLECTION_NOT_USED" : { "code" : 1924, "message" : "The edge collection is not used in the edge definitions." },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "multi use of edge collection in edge def" },
"ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : "edge collection already used in edge def" },
"ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "missing graph name" },
"ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION" : { "code" : 1923, "message" : "malformed edge def" },
"ERROR_GRAPH_NOT_FOUND" : { "code" : 1924, "message" : "graph not found" },
"ERROR_GRAPH_DUPLICATE" : { "code" : 1925, "message" : "graph already exists" },
"ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST" : { "code" : 1926, "message" : "collection does not exist" },
"ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX" : { "code" : 1927, "message" : "not a vertex collection" },
"ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION" : { "code" : 1928, "message" : "not in orphan collection" },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
"SIMPLE_CLIENT_COULD_NOT_CONNECT" : { "code" : 2001, "message" : "could not connect to server" },
"SIMPLE_CLIENT_COULD_NOT_WRITE" : { "code" : 2002, "message" : "could not write to server" },
@ -222,7 +227,6 @@
"ERROR_ARANGO_INDEX_BITARRAY_INSERT_ITEM_UNSUPPORTED_VALUE" : { "code" : 3413, "message" : "bitarray index insert failure - document attribute value unsupported in index" },
"ERROR_ARANGO_INDEX_BITARRAY_CREATION_FAILURE_DUPLICATE_ATTRIBUTES" : { "code" : 3415, "message" : "bitarray index creation failure - one or more index attributes are duplicated." },
"ERROR_ARANGO_INDEX_BITARRAY_CREATION_FAILURE_DUPLICATE_VALUES" : { "code" : 3417, "message" : "bitarray index creation failure - one or more index attribute values are duplicated." },
"ERROR_APP_ALREADY_EXISTS" : { "code": 4000, "message": "App is already installed" },
"RESULT_KEY_EXISTS" : { "code" : 10000, "message" : "element not inserted into structure, because key already exists" },
"RESULT_ELEMENT_EXISTS" : { "code" : 10001, "message" : "element not inserted into structure, because it already exists" },
"RESULT_KEY_NOT_FOUND" : { "code" : 10002, "message" : "key not found in structure" },

View File

@ -0,0 +1,431 @@
/*jslint indent: 2, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, sloppy: true */
/*global require, SYS_GETLINE, SYS_LOG, jqconsole */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "console"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-2013 triAGENS 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 triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function () {
// cannot use strict here as we are going to delete globals
var exports = require("console");
var sprintf = require("internal").sprintf;
var inspect = require("internal").inspect;
// -----------------------------------------------------------------------------
// --SECTION-- Module "console"
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief group level
////////////////////////////////////////////////////////////////////////////////
var groupLevel = "";
////////////////////////////////////////////////////////////////////////////////
/// @brief timers
////////////////////////////////////////////////////////////////////////////////
var timers = { };
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief internal logging
////////////////////////////////////////////////////////////////////////////////
var log;
try {
// this will work when we are in arangod but not in the browser / web interface
log = SYS_LOG;
delete SYS_LOG;
}
catch (err) {
// this will work in the web interface
log = function (level, message) {
if (jqconsole) {
jqconsole.Write(message + "\n", 'jssuccess');
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief internal logging with group level
////////////////////////////////////////////////////////////////////////////////
function logGroup (level, msg) {
'use strict';
log(level, groupLevel + msg);
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief assert
////////////////////////////////////////////////////////////////////////////////
exports.assert = function (condition) {
'use strict';
if (condition) {
return;
}
var args = Array.prototype.slice.call(arguments, 1);
var msg;
try {
msg = sprintf.apply(sprintf, args);
}
catch (err) {
msg = err + ": " + args;
}
logGroup("error", msg);
require('assert').ok(condition, msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief debug
////////////////////////////////////////////////////////////////////////////////
exports.debug = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
logGroup("debug", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief debugLines
////////////////////////////////////////////////////////////////////////////////
exports.debugLines = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
var a = msg.split("\n");
var i;
for (i = 0; i < a.length; ++i) {
logGroup("debug", a[i]);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief dir
////////////////////////////////////////////////////////////////////////////////
exports.dir = function (object) {
'use strict';
logGroup("info", inspect(object));
};
////////////////////////////////////////////////////////////////////////////////
/// @brief error
////////////////////////////////////////////////////////////////////////////////
exports.error = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
logGroup("error", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief errorLines
////////////////////////////////////////////////////////////////////////////////
exports.errorLines = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
var a = msg.split("\n");
var i;
for (i = 0; i < a.length; ++i) {
logGroup("error", a[i]);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief getline
////////////////////////////////////////////////////////////////////////////////
if (typeof SYS_GETLINE !== "undefined") {
exports.getline = SYS_GETLINE;
delete SYS_GETLINE;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief group
////////////////////////////////////////////////////////////////////////////////
exports.group = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
groupLevel = groupLevel + " ";
logGroup("info", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief groupCollapsed
////////////////////////////////////////////////////////////////////////////////
exports.groupCollapsed = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
logGroup("info", msg);
groupLevel = groupLevel + " ";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief groupEnd
////////////////////////////////////////////////////////////////////////////////
exports.groupEnd = function () {
'use strict';
groupLevel = groupLevel.substr(2);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief info
////////////////////////////////////////////////////////////////////////////////
exports.info = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
logGroup("info", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief infoLines
////////////////////////////////////////////////////////////////////////////////
exports.infoLines = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
var a = msg.split("\n");
var i;
for (i = 0; i < a.length; ++i) {
logGroup("info", a[i]);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief log
////////////////////////////////////////////////////////////////////////////////
exports.log = exports.info;
////////////////////////////////////////////////////////////////////////////////
/// @brief logLines
////////////////////////////////////////////////////////////////////////////////
exports.logLines = exports.infoLines;
////////////////////////////////////////////////////////////////////////////////
/// @brief time
////////////////////////////////////////////////////////////////////////////////
exports.time = function (label) {
'use strict';
if (typeof label !== 'string') {
throw new Error('label must be a string');
}
timers[label] = Date.now();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief timeEnd
////////////////////////////////////////////////////////////////////////////////
exports.timeEnd = function(label) {
'use strict';
var time = timers[label];
if (! time) {
throw new Error('No such label: ' + label);
}
var duration = Date.now() - time;
delete timers[label];
logGroup('%s: %dms', label, duration);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief trace
////////////////////////////////////////////////////////////////////////////////
exports.trace = function () {
var err = new Error();
err.name = 'trace';
err.message = sprintf.apply(sprintf, arguments);
Error.captureStackTrace(err, exports.trace);
logGroup("info", err.stack);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief warn
////////////////////////////////////////////////////////////////////////////////
exports.warn = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
logGroup("warning", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief warnLines
////////////////////////////////////////////////////////////////////////////////
exports.warnLines = function () {
'use strict';
var msg;
try {
msg = sprintf.apply(sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
var a = msg.split("\n");
var i;
for (i = 0; i < a.length; ++i) {
logGroup("warning", a[i]);
}
};
}());
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
// End:

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
/*global require, ArangoConnection, print, SYS_ARANGO */
/*global require, ArangoConnection, print, SYS_ARANGO, window */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
@ -300,6 +300,32 @@
internal.output(level, ": ", msg, "\n");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sprintf wrapper
////////////////////////////////////////////////////////////////////////////////
try {
if (window) {
internal.sprintf = function (format) {
var n = arguments.length;
if (n === 0) {
return "";
}
if (n <= 1) {
return String(format);
}
var i = 0;
return format.replace(/%[dfs]/, function (match) {
return String(arguments[++i]);
});
};
}
}
catch (err) {
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,432 @@
module.define("org/arangodb/graph-blueprint", function(exports, module) {
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
/// @brief Graph functionality
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2012 triagens 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 triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb"),
is = require("org/arangodb/is"),
common = require("org/arangodb/graph-common"),
Edge = common.Edge,
Graph = common.Graph,
Vertex = common.Vertex,
GraphArray = common.GraphArray,
Iterator = common.Iterator,
GraphAPI = require ("org/arangodb/api/graph").GraphAPI;
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief changes a property of an edge
////////////////////////////////////////////////////////////////////////////////
Edge.prototype.setProperty = function (name, value) {
var results,
update = this._properties;
update[name] = value;
this._graph.emptyCachedPredecessors();
results = GraphAPI.putEdge(this._graph._properties._key, this._properties._key, update);
this._properties = results.edge;
return name;
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Vertex
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new vertex object
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief inbound and outbound edges
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.edges = function (direction, labels) {
var edge,
edges = new GraphArray(),
cursor;
cursor = GraphAPI.postEdges(this._graph._vertices._database, this._graph._properties._key, this, {
filter : { direction : direction, labels: labels }
});
while (cursor.hasNext()) {
edge = new Edge(this._graph, cursor.next());
edges.push(edge);
}
return edges;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief inbound edges with given label
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.getInEdges = function () {
var labels = Array.prototype.slice.call(arguments);
return this.edges("in", labels);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief outbound edges with given label
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.getOutEdges = function () {
var labels = Array.prototype.slice.call(arguments);
return this.edges("out", labels);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief in- or outbound edges with given label
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.getEdges = function () {
var labels = Array.prototype.slice.call(arguments);
return this.edges("any", labels);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief inbound edges
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.inbound = function () {
return this.getInEdges();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief outbound edges
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.outbound = function () {
return this.getOutEdges();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief changes a property of a vertex
////////////////////////////////////////////////////////////////////////////////
Vertex.prototype.setProperty = function (name, value) {
var results,
update = this._properties;
update[name] = value;
results = GraphAPI.putVertex(this._graph._properties._key, this._properties._key, update);
this._properties = results.vertex;
return name;
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief constructs a new graph object
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.initialize = function (name, vertices, edges) {
var results;
if (is.notExisty(vertices) && is.notExisty(edges)) {
results = GraphAPI.getGraph(name);
} else {
if (typeof vertices === 'object' && typeof vertices.name === 'function') {
vertices = vertices.name();
}
if (typeof edges === 'object' && typeof edges.name === 'function') {
edges = edges.name();
}
results = GraphAPI.postGraph({
_key: name,
vertices: vertices,
edges: edges
});
}
this._properties = results.graph;
this._vertices = arangodb.db._collection(this._properties.edgeDefinitions[0].from[0]);
this._edges = arangodb.db._collection(this._properties.edgeDefinitions[0].collection);
// and dictionary for vertices and edges
this._verticesCache = {};
this._edgesCache = {};
// and store the cashes
this.predecessors = {};
this.distances = {};
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief return all graphs
////////////////////////////////////////////////////////////////////////////////
Graph.getAll = function () {
return GraphAPI.getAllGraphs();
};
////////////////////////////////////////////////////////////////////////////////
/// @brief static delete method
////////////////////////////////////////////////////////////////////////////////
Graph.drop = function (name) {
GraphAPI.deleteGraph(name);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief drops the graph, the vertices, and the edges
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.drop = function () {
GraphAPI.deleteGraph(this._properties._key);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief saves an edge to the graph
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._saveEdge = function(id, out_vertex_id, in_vertex_id, params) {
var results;
this.emptyCachedPredecessors();
params._key = id;
params._from = out_vertex_id;
params._to = in_vertex_id;
results = GraphAPI.postEdge(this._properties._key, params);
return new Edge(this, results.edge);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief saves a vertex to the graph
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._saveVertex = function (id, params) {
var results;
if (is.existy(id)) {
params._key = id;
}
results = GraphAPI.postVertex(this._properties._key, params);
return new Vertex(this, results.vertex);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief replace a vertex in the graph
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._replaceVertex = function (id, data) {
GraphAPI.putVertex(this._properties._key, id, data);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief replace an edge in the graph
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._replaceEdge = function (id, data) {
GraphAPI.putEdge(this._properties._key, id, data);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns a vertex given its id
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.getVertex = function (id) {
var results = GraphAPI.getVertex(this._properties._key, id);
if (is.notExisty(results)) {
return null;
}
return new Vertex(this, results.vertex);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns an iterator for all vertices
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.getVertices = function () {
var cursor = GraphAPI.getVertices(this._vertices._database, this._properties._key, {}),
graph = this,
wrapper = function(object) {
return new Vertex(graph, object);
};
return new Iterator(wrapper, cursor, "[vertex iterator]");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns an edge given its id
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.getEdge = function (id) {
var results = GraphAPI.getEdge(this._properties._key, id);
if (is.notExisty(results)) {
return null;
}
return new Edge(this, results.edge);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief returns an iterator for all edges
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.getEdges = function () {
var cursor = GraphAPI.getEdges(this._vertices._database, this._properties._key, {}),
graph = this,
wrapper = function(object) {
return new Edge(graph, object);
};
return new Iterator(wrapper, cursor, "[edge iterator]");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief removes a vertex and all in- or out-bound edges
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.removeVertex = function (vertex) {
this.emptyCachedPredecessors();
GraphAPI.deleteVertex(this._properties._key, vertex._properties._key);
vertex._properties = undefined;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief removes an edge
////////////////////////////////////////////////////////////////////////////////
Graph.prototype.removeEdge = function (edge) {
this.emptyCachedPredecessors();
GraphAPI.deleteEdge(this._properties._key, edge._properties._key);
this._edgesCache[edge._properties._id] = undefined;
edge._properties = undefined;
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- MODULE EXPORTS
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoGraph
/// @{
////////////////////////////////////////////////////////////////////////////////
exports.Edge = Edge;
exports.Graph = Graph;
exports.Vertex = Vertex;
exports.GraphArray = GraphArray;
require("org/arangodb/graph/algorithms-common");
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:
});

View File

@ -5,7 +5,7 @@
<meta charset="utf-8">
<title>ArangoDB Web Interface</title>
<meta name="description" content="ArangoDB Admin Web Interface">
<meta name="author" content="Heiko Kernbach, Michael Hacksteina, Guido Schwab">
<meta name="author" content="Heiko Kernbach, Michael Hackstein, Guido Schwab">
<link href="css/style.css" rel="stylesheet">
<link href="css/sass.css" rel="stylesheet">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">

View File

@ -102,6 +102,7 @@
"frontend/js/bootstrap/module-internal.js",
"frontend/js/client/bootstrap/module-internal.js",
"frontend/js/client/client.js",
"frontend/js/bootstrap/module-console.js",
"frontend/js/models/arangoCollectionModel.js",
"frontend/js/models/arangoDatabase.js",
"frontend/js/models/arangoDocument.js",

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
/*global require, ArangoConnection, print, SYS_ARANGO */
/*global require, ArangoConnection, print, SYS_ARANGO, window */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
@ -300,6 +300,32 @@
internal.output(level, ": ", msg, "\n");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sprintf wrapper
////////////////////////////////////////////////////////////////////////////////
try {
if (window) {
internal.sprintf = function (format) {
var n = arguments.length;
if (n === 0) {
return "";
}
if (n <= 1) {
return String(format);
}
var i = 0;
return format.replace(/%[dfs]/, function (match) {
return String(arguments[++i]);
});
};
}
}
catch (err) {
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -104,6 +104,7 @@
"ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING" : { "code" : 1234, "message" : "index insertion warning - attribute missing in document" },
"ERROR_ARANGO_INDEX_CREATION_FAILED" : { "code" : 1235, "message" : "index creation failed" },
"ERROR_ARANGO_DATAFILE_FULL" : { "code" : 1300, "message" : "datafile full" },
"ERROR_ARANGO_EMPTY_DATADIR" : { "code" : 1301, "message" : "server database directory is empty" },
"ERROR_REPLICATION_NO_RESPONSE" : { "code" : 1400, "message" : "no response" },
"ERROR_REPLICATION_INVALID_RESPONSE" : { "code" : 1401, "message" : "invalid response" },
"ERROR_REPLICATION_MASTER_ERROR" : { "code" : 1402, "message" : "master error" },
@ -169,8 +170,6 @@
"ERROR_QUERY_GEO_INDEX_MISSING" : { "code" : 1570, "message" : "no suitable geo index found for geo restriction on '%s'" },
"ERROR_QUERY_FULLTEXT_INDEX_MISSING" : { "code" : 1571, "message" : "no suitable fulltext index found for fulltext query on '%s'" },
"ERROR_QUERY_INVALID_DATE_VALUE" : { "code" : 1572, "message" : "invalid date value" },
"ERROR_QUERY_MULTI_MODIFY" : { "code" : 1573, "message" : "multi-modify query" },
"ERROR_QUERY_MODIFY_IN_SUBQUERY" : { "code" : 1574, "message" : "modify in subquery" },
"ERROR_QUERY_FUNCTION_INVALID_NAME" : { "code" : 1580, "message" : "invalid user function name" },
"ERROR_QUERY_FUNCTION_INVALID_CODE" : { "code" : 1581, "message" : "invalid user function code" },
"ERROR_QUERY_FUNCTION_NOT_FOUND" : { "code" : 1582, "message" : "user function '%s()' not found" },
@ -179,7 +178,6 @@
"ERROR_TRANSACTION_NESTED" : { "code" : 1651, "message" : "nested transactions detected" },
"ERROR_TRANSACTION_UNREGISTERED_COLLECTION" : { "code" : 1652, "message" : "unregistered collection used in transaction" },
"ERROR_TRANSACTION_DISALLOWED_OPERATION" : { "code" : 1653, "message" : "disallowed operation inside transaction" },
"ERROR_TRANSACTION_ABORTED" : { "code" : 1654, "message" : "transaction aborted" },
"ERROR_USER_INVALID_NAME" : { "code" : 1700, "message" : "invalid user name" },
"ERROR_USER_INVALID_PASSWORD" : { "code" : 1701, "message" : "invalid password" },
"ERROR_USER_DUPLICATE" : { "code" : 1702, "message" : "duplicate user" },
@ -209,6 +207,15 @@
"ERROR_GRAPH_COULD_NOT_CHANGE_EDGE" : { "code" : 1908, "message" : "could not change edge" },
"ERROR_GRAPH_TOO_MANY_ITERATIONS" : { "code" : 1909, "message" : "too many iterations" },
"ERROR_GRAPH_INVALID_FILTER_RESULT" : { "code" : 1910, "message" : "invalid filter result" },
"ERROR_GRAPH_COLLECTION_MULTI_USE" : { "code" : 1920, "message" : "multi use of edge collection in edge def" },
"ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS" : { "code" : 1921, "message" : "edge collection already used in edge def" },
"ERROR_GRAPH_CREATE_MISSING_NAME" : { "code" : 1922, "message" : "missing graph name" },
"ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION" : { "code" : 1923, "message" : "malformed edge def" },
"ERROR_GRAPH_NOT_FOUND" : { "code" : 1924, "message" : "graph not found" },
"ERROR_GRAPH_DUPLICATE" : { "code" : 1925, "message" : "graph already exists" },
"ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST" : { "code" : 1926, "message" : "collection does not exist" },
"ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX" : { "code" : 1927, "message" : "not a vertex collection" },
"ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION" : { "code" : 1928, "message" : "not in orphan collection" },
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },

View File

@ -1,5 +1,5 @@
/*jslint indent: 2, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, sloppy: true */
/*global require, SYS_GETLINE, SYS_LOG */
/*global require, SYS_GETLINE, SYS_LOG, jqconsole */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "console"
@ -64,8 +64,21 @@
/// @brief internal logging
////////////////////////////////////////////////////////////////////////////////
var log = SYS_LOG;
delete SYS_LOG;
var log;
try {
// this will work when we are in arangod but not in the browser / web interface
log = SYS_LOG;
delete SYS_LOG;
}
catch (err) {
// this will work in the web interface
log = function (level, message) {
if (jqconsole) {
jqconsole.Write(message + "\n", 'jssuccess');
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief internal logging with group level

View File

@ -1709,6 +1709,7 @@ var Graph = function(graphName, edgeDefinitions, vertexCollections, edgeCollecti
createHiddenProperty(this, "__edgeDefinitions", edgeDefinitions);
createHiddenProperty(this, "__idsToRemove", []);
createHiddenProperty(this, "__collectionsToLock", []);
createHiddenProperty(this, "__orphanCollections", []);
// fills this.__idsToRemove and this.__collectionsToLock
var removeEdge = function (edgeId, options) {
@ -1957,6 +1958,12 @@ var checkIfMayBeDropped = function(colName, graphName, graphs) {
}
);
}
var orphanCollections = graph.orphanCollections;
if (orphanCollections) {
if (orphanCollections.indexOf(colName) !== -1) {
return false;
}
}
}
);
@ -2557,6 +2564,7 @@ Graph.prototype._editEdgeDefinitions = function(edgeDefinition, dropCollections)
findOrCreateCollectionsByEdgeDefinitions([edgeDefinition]);
if (dropCollections !== false) {
graphs = getGraphCollection().toArray();
//eval collection to be dropped
dropCandidates = currentEdgeDefinition.from;
currentEdgeDefinition.to.forEach(
@ -2689,31 +2697,129 @@ Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections
};
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_general_graph__addVertexCollection
/// Adds a vertex collection to the graph. If the collection does not exist, it will be created.
/// @startDocuBlock JSF_general_graph__addOrphanCollection
/// Adds a vertex collection to the set of orphan collections of the graph. If the
/// collection does not exist, it will be created.
///
/// `general-graph._addVertexCollection(vertexCollectionName, createCollection)`
/// `general-graph._addOrphanCollection(orphanCollectionName, createCollection)`
///
/// *vertexCollectionName* - string : name of vertex collection.
/// *orphanCollectionName* - string : name of vertex collection.
/// *createCollection* - bool : if true the collection will be created if it does not exist. Default: true.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addeleteVertexCollection}
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addOrphanCollection}
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
/// var g = examples._create("myGraph", [ed1, ed2]);
/// g._addVertexCollection("myVC3", true);
/// g._addOrphanCollection("myVC3", true);
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._addVertexCollection = function(edgeCollection, dropCollections) {
Graph.prototype._addOrphanCollection = function(vertexCollection, createCollection) {
//check edgeCollection
var ec = db._collection(vertexCollection);
var err;
if (ec === null) {
if (createCollection !== false) {
db._create(vertexCollection);
} else {
err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
err.errorMessage = vertexCollection + arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
throw err;
}
} else if (ec.type() !== 2) {
err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code;
err.errorMessage = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message;
throw err;
}
this.__orphanCollections.push(vertexCollection);
db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
};
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_general_graph__getOrphanCollections
/// Returns all vertex collections of the graph, that are not used in an edge definition.
///
/// `general-graph._getOrphanCollections()`
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
/// var g = examples._create("myGraph", [ed1]);
/// g._addOrphanCollection("myVC3, true);
/// g._getOrphanCollections();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._getOrphanCollections = function() {
return this.__orphanCollections;
};
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_general_graph__removeOrphanCollection
/// Removes an orphan collection from the graph and deletes the collection, if it is not
/// used in any graph.
///
/// `general-graph._removeOrphanCollection()`
///
/// *orphanCollectionName* - string : name of vertex collection.
/// *dropCollection* - bool : if true the collection will be dropped if it is not used in any graph.
/// Default: true.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
/// var g = examples._create("myGraph", [ed1]);
/// g._addOrphanCollection("myVC3, true);
/// g._addOrphanCollection("myVC4, true);
/// g._getOrphanCollections();
/// g._removeOrphanCollection("myVC3");
/// g._getOrphanCollections();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// @endDocuBlock
///
////////////////////////////////////////////////////////////////////////////////
Graph.prototype._removeOrphanCollection = function(orphanCollectionName, dropCollection) {
var err;
if (db._collection(orphanCollectionName) === null) {
err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
err.errorMessage = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
throw err;
}
var index = this.__orphanCollections.indexOf(orphanCollectionName);
if (index === -1) {
err = new ArangoError();
err.errorNum = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code;
err.errorMessage = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message;
throw err;
}
this.__orphanCollections.splice(index, 1);
if (dropCollection !== false) {
var graphs = getGraphCollection().toArray();
if (checkIfMayBeDropped(orphanCollectionName, null, graphs)) {
db._drop(orphanCollectionName);
}
}
};

View File

@ -307,7 +307,7 @@ function GeneralGraphCreationSuite() {
);
fail();
} catch (err) {
assertEqual(err.errorMessage, "a graph name is required to create a graph.");
assertEqual(err.errorMessage, ERRORS.ERROR_GRAPH_CREATE_MISSING_NAME.message);
}
},
@ -2497,6 +2497,118 @@ function GeneralGraphCommonNeighborsSuite() {
};
}
function OrphanCollectionSuite() {
var prefix = "UnitTestGraphVertexCollection",
g1,
g2,
gN1 = prefix + "Graph1",
gN2 = prefix + "Graph2",
eC1 = prefix + "EdgeCollection1",
eC2 = prefix + "EdgeCollection2",
vC1 = prefix + "VertexCollection1",
vC2 = prefix + "VertexCollection2",
vC3 = prefix + "VertexCollection3",
vC4 = prefix + "VertexCollection4",
vC5 = prefix + "VertexCollection5";
return {
setUp : function() {
try {
arangodb.db._collection("_graphs").remove(gN1);
} catch (ignore) {
}
try {
arangodb.db._collection("_graphs").remove(gN2);
} catch (ignore) {
}
g1 = graph._create(
gN1,
graph._edgeDefinitions(
graph._directedRelationDefinition(
eC1, [vC1], [vC1, vC2]
)
)
);
g2 = graph._create(
gN2,
graph._edgeDefinitions(
graph._directedRelationDefinition(
eC2, [vC3], [vC1]
)
)
);
},
tearDown : function() {
graph._drop(gN1);
graph._drop(gN2);
try {db[vC1].drop()} catch (e) {}
try {db[vC4].drop()} catch (e) {}
},
test_getOrphanCollection: function() {
assertEqual(g1._getOrphanCollections(), []);
},
test_addOrphanCollection1: function() {
g1._addOrphanCollection(vC1, false);
assertEqual(g1._getOrphanCollections(), [vC1]);
},
test_addOrphanCollection2: function() {
try {
g1._addOrphanCollection(vC4, false);
} catch (e) {
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
assertEqual(e.errorMessage, vC4 + ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
}
assertTrue(db._collection(vC4) === null);
assertEqual(g1._getOrphanCollections(), []);
},
test_addOrphanCollection3: function() {
try {
g1._addOrphanCollection(eC1, false);
} catch (e) {
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code);
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message);
}
assertTrue(db._collection(vC4) === null);
assertEqual(g1._getOrphanCollections(), []);
},
test_removeOrphanCollection1: function() {
var name = "completelyNonsenseNameForACollectionBLUBBBBB"
try {
g1._removeOrphanCollection(name);
} catch (e) {
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
}
},
test_removeOrphanCollection2: function() {
g1._addOrphanCollection(vC4, true);
g1._addOrphanCollection(vC5, true);
assertEqual(g1._getOrphanCollections(), [vC4, vC5]);
g1._removeOrphanCollection(vC4, false);
assertEqual(g1._getOrphanCollections(), [vC5]);
try {
g1._removeOrphanCollection(vC4);
} catch (e) {
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code);
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message);
}
}
};
}
// -----------------------------------------------------------------------------
// --SECTION-- main
@ -2511,7 +2623,7 @@ jsunity.run(GeneralGraphAQLQueriesSuite);
jsunity.run(EdgesAndVerticesSuite);
jsunity.run(GeneralGraphCreationSuite);
jsunity.run(ChainedFluentAQLResultsSuite);
//jsunity.run(VertexCollectionChainedFluentAQLResultsSuite);
jsunity.run(OrphanCollectionSuite);
return jsunity.done();

View File

@ -5130,7 +5130,7 @@ function IS_EXAMPLE_SET (example) {
/// @startDocuBlock JSF_ahuacatl_general_graph_shortest_paths
///
/// `GRAPH_SHORTEST_PATH (graphName, startVertexExample, endVertexExample, options)`
/// *The GRAPH\_SHORTEST\_PATH function returns all paths of a graph.*
/// *The GRAPH\_SHORTEST\_PATH function returns all shortest paths of a graph.*
///
/// This function determines all shortest paths in a graph identified by *graphName*.
/// The function accepts an id, an example, a list of examples
@ -5138,7 +5138,7 @@ function IS_EXAMPLE_SET (example) {
/// start and end vertex. If one wants to calls this function to receive nearly all
/// shortest paths for a graph the
/// option *algorithm* should be set to *Floyd-Warshall* to increase performance.
/// If no algorithm is given in the options the function chooses the appropriate
/// If no algorithm is provided in the options the function chooses the appropriate
/// one (either *Floyd-Warshall* or *Dijsktra*) according to its parameters.
/// The length of a path is by default the amount of edges from one start vertex to
/// an end vertex. The option weight allows the user to define an edge attribute
@ -5384,6 +5384,7 @@ function GRAPH_TRAVERSAL_TREE (vertexCollection,
/// *The GRAPH\_DISTANCE\_TO function returns all paths and there distance within a graph.*
///
/// This function is a wrapper of [GRAPH\_SHORTEST\_PATH](#SUBSECTION GRAPH_SHORTEST_PATH).
/// It does not return the actual path but only the distance between two vertices.
///
////////////////////////////////////////////////////////////////////////////////
function GENERAL_GRAPH_DISTANCE_TO (graphName,
@ -5689,7 +5690,7 @@ function GENERAL_GRAPH_NEIGHBORS (graphName,
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_ahuacatl_general_graph_neighbors
/// @startDocuBlock JSF_ahuacatl_general_graph_edges
///
/// `GRAPH_EDGES (graphName, vertexExample, options)`
/// *The GRAPH\_EDGES function returns all edges of vertices.*
@ -5919,28 +5920,27 @@ function TRANSFER_GENERAL_GRAPH_NEIGHBORS_RESULT (result) {
///
/// @EXAMPLES
///
/// A route planner example, all neighbors of locations with a distance of
/// either 700 or 600.:
/// A route planner example, all common neighbors of capitals.
///
/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertices1}
/// ~ var db = require("internal").db;
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var g = examples.loadGraph("routeplanner");
/// |db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
/// |+"'routeplanner', {}) RETURN e"
/// |+"'routeplanner', {isCapital : true}, {isCapital : true}) RETURN e"
/// ).toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
/// A route planner example, all outbound neighbors of munich with a maximal
/// depth of 2 :
/// A route planner example, all common outbound neighbors of munich with any other location
/// which have a maximal depth of 2 :
///
/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphVertices2}
/// ~ var db = require("internal").db;
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
/// var g = examples.loadGraph("routeplanner");
/// |db._query("FOR e IN GRAPH_COMMON_NEIGHBORS("
/// |+"'routeplanner', {}, {direction : 'any', vertexCollectionRestriction" +
/// |" : 'city'}) RETURN e"
/// |+"'routeplanner', 'city/Munich', {}, {direction : 'outbound', maxDepth : 2}, "+
/// | "{direction : 'outbound', maxDepth : 2}) RETURN e"
/// ).toArray();
/// @END_EXAMPLE_ARANGOSH_OUTPUT
///
@ -6149,7 +6149,7 @@ function GENERAL_GRAPH_COMMON_PROPERTIES (
///
/// `GRAPH_ABSOLUTE_ECCENTRICITY (graphName, vertexExample, options)`
/// *The GRAPH\_ABSOLUTE\_ECCENTRICITY function returns the
/// [eccentricity](http://en.wikipedia.org/wiki/Distance_(graph_theory))
/// [eccentricity](http://en.wikipedia.org/wiki/Distance_%28graph_theory%29)
/// of the vertices defined by the examples.
///
/// The function accepts an id, an example, a list of examples or even an empty
@ -6260,7 +6260,7 @@ function GENERAL_GRAPH_ABSOLUTE_ECCENTRICITY (graphName, vertexExample, options)
///
/// `GRAPH_ECCENTRICITY (graphName, options)`
/// *The GRAPH\_ECCENTRICITY function returns the normalized
/// [eccentricity](http://en.wikipedia.org/wiki/Distance_(graph_theory))
/// [eccentricity](http://en.wikipedia.org/wiki/Distance_%28graph_theory%29)
/// of the graphs vertices
///
/// * String *graphName* : The name of the graph.
@ -6737,7 +6737,7 @@ function GENERAL_GRAPH_BETWEENNESS (graphName, options) {
///
/// `GRAPH_RADIUS (graphName, options)`
/// *The GRAPH\_RADIUS function returns the
/// [radius](http://en.wikipedia.org/wiki/Eccentricity_(graph_theory))
/// [radius](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
/// of a graph.
///
/// * String *graphName* : The name of the graph.
@ -6829,7 +6829,7 @@ function GENERAL_GRAPH_RADIUS (graphName, options) {
///
/// `GRAPH_DIAMETER (graphName, options)`
/// *The GRAPH\_DIAMETER function returns the
/// [diameter](http://en.wikipedia.org/wiki/Eccentricity_(graph_theory))
/// [diameter](http://en.wikipedia.org/wiki/Eccentricity_%28graph_theory%29)
/// of a graph.
///
/// * String *graphName* : The name of the graph.

View File

@ -30,10 +30,9 @@
/// @author Copyright 2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var internal = require("internal");
var cluster = require("org/arangodb/cluster");
var fs = require("fs");
var db = internal.db;
var db = require("org/arangodb").db;
var console = require("console");
// -----------------------------------------------------------------------------
@ -124,7 +123,7 @@ exports.databaseVersion = function () {
}
// path to the VERSION file
var versionFile = internal.db._path() + "/VERSION";
var versionFile = db._path() + "/VERSION";
var lastVersion = null;
// VERSION file exists, read its contents
@ -152,11 +151,11 @@ exports.databaseVersion = function () {
}
// extract server version
var currentServerVersion = internal.db._version().match(/^(\d+\.\d+).*$/);
var currentServerVersion = db._version().match(/^(\d+\.\d+).*$/);
// server version is invalid for some reason
if (! currentServerVersion) {
logger.error("Unexpected ArangoDB server version: " + internal.db._version());
logger.error("Unexpected ArangoDB server version: " + db._version());
return { result: exports.NO_SERVER_VERSION };
}

View File

@ -30,11 +30,16 @@
var Controller = require("org/arangodb/foxx/controller").Controller,
Model = require("org/arangodb/foxx/model").Model,
Repository = require("org/arangodb/foxx/repository").Repository;
Repository = require("org/arangodb/foxx/repository").Repository,
manager = require("org/arangodb/foxx/manager"),
arangodb = require("org/arangodb");
exports.Controller = Controller;
exports.Model = Model;
exports.Repository = Repository;
exports.requireApp = function(path) {
return manager.mountedApp(arangodb.normalizeURL('/' + path));
};
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE

View File

@ -115,6 +115,12 @@ Controller = function (context, options) {
context.foxxes.push(this);
if (is.existy(context.manifest.rootElement)) {
this.rootElement =context.manifest.rootElement;
} else {
this.rootElement = false;
}
this.applicationContext = context;
};
@ -123,22 +129,8 @@ extend(Controller.prototype, {
collection: function (name) {
'use strict';
var collection, cname, prefix;
prefix = this.collectionPrefix;
if (prefix === "") {
cname = name;
} else {
cname = prefix + "_" + name;
}
cname = cname.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
collection = db._collection(cname);
if (!collection) {
throw new Error("collection with name '" + cname + "' does not exist.");
}
return collection;
require('console').log('Controller#collection is deprecated, use appContext#collection instead');
return this.applicationContext.collection(name);
},
////////////////////////////////////////////////////////////////////////////////
@ -156,7 +148,7 @@ extend(Controller.prototype, {
handleRequest: function (method, route, callback) {
'use strict';
var newRoute = internal.constructRoute(method, route, callback),
requestContext = new RequestContext(this.allRoutes, this.models, newRoute),
requestContext = new RequestContext(this.allRoutes, this.models, newRoute, this.rootElement),
summary;
this.routingInfo.routes.push(newRoute);
@ -294,7 +286,7 @@ extend(Controller.prototype, {
///
/// This handles requests from the HTTP verb `delete`. See above for the
/// arguments you can give.
///
///
/// @warning Do not forget that `delete` is a reserved word in JavaScript and
/// therefore needs to be called as app['delete']. There is also an alias `del`
/// for this very reason.

View File

@ -102,7 +102,7 @@ function checkManifest (filename, mf) {
// add a default (empty) description
mf.description = "";
}
if (mf.hasOwnProperty("apps")) {
console.warn("Manifest '%s' still contains the deprecated 'apps' attribute. " +
"Please change the attribute name to 'controllers'.", filename);
@ -121,7 +121,7 @@ function checkManifest (filename, mf) {
"assets": [ false, "object" ],
"author": [ false, "string" ],
"contributors": [ false, "array" ],
"controllers": [ true, "object" ],
"controllers": [ false, "object" ],
"defaultDocument": [ false, "string" ],
"description": [ true, "string" ],
"engines": [ false, "object" ],
@ -136,6 +136,7 @@ function checkManifest (filename, mf) {
"teardown": [ false, "string" ],
"thumbnail": [ false, "string" ],
"version": [ true, "string" ],
"rootElement": [ false, "boolean" ],
"exports": [ false, "object" ]
};
@ -148,8 +149,8 @@ function checkManifest (filename, mf) {
var actualType = Array.isArray(mf[att]) ? "array" : typeof(mf[att]);
if (actualType !== expectedType) {
console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'",
filename,
console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'",
filename,
actualType,
expectedType,
att);
@ -160,8 +161,8 @@ function checkManifest (filename, mf) {
// attribute not present in manifest
if (expected[att][0]) {
// required attribute
console.error("Manifest '%s' does not provide required attribute '%s'",
filename,
console.error("Manifest '%s' does not provide required attribute '%s'",
filename,
att);
failed = true;
@ -169,7 +170,7 @@ function checkManifest (filename, mf) {
}
}
}
if (failed) {
throw new Error("Manifest '%s' is invalid/incompatible. Please check the error logs.");
}
@ -178,8 +179,8 @@ function checkManifest (filename, mf) {
for (att in mf) {
if (mf.hasOwnProperty(att)) {
if (! expected.hasOwnProperty(att)) {
console.warn("Manifest '%s' contains an unknown attribute '%s'",
filename,
console.warn("Manifest '%s' contains an unknown attribute '%s'",
filename,
att);
}
}
@ -208,6 +209,10 @@ function extendContext (context, app, root) {
return replaced;
};
context.collection = function (name) {
return arangodb.db._collection(this.collectionName(name));
};
context.path = function (name) {
return fs.join(root, app._path, name);
};
@ -279,7 +284,7 @@ function buildAssetContent (app, assets, basePath) {
var excludeFile = function (name) {
var parts = name.split('/');
if (parts.length > 0) {
var last = parts[parts.length - 1];
@ -303,8 +308,8 @@ function buildAssetContent (app, assets, basePath) {
if (match !== null) {
m = fs.listTree(fs.join(basePath, match[1]));
// files are sorted in file-system order.
// files are sorted in file-system order.
// this makes the order non-portable
// we'll be sorting the files now using JS sort
// so the order is more consistent across multiple platforms
@ -312,7 +317,7 @@ function buildAssetContent (app, assets, basePath) {
for (i = 0; i < m.length; ++i) {
var filename = fs.join(basePath, match[1], m[i]);
if (! excludeFile(m[i])) {
if (fs.isFile(filename)) {
files.push(filename);
@ -322,7 +327,7 @@ function buildAssetContent (app, assets, basePath) {
}
else {
match = reAll.exec(asset);
if (match !== null) {
throw new Error("Not implemented");
}
@ -367,7 +372,7 @@ function buildFileAsset (app, path, basePath, asset) {
type = asset.contentType;
}
// path contains a dot, derive content type from path
// path contains a dot, derive content type from path
else if (path.match(/\.[a-zA-Z0-9]+$/)) {
type = arangodb.guessContentType(path);
}
@ -399,7 +404,7 @@ function buildDevelopmentAssetRoute (app, path, basePath, asset) {
return {
url: { match: path },
action: {
action: {
callback: function (req, res) {
var c = buildFileAsset(app, path, basePath, asset);
@ -495,7 +500,7 @@ function installAssets (app, routes) {
function executeAppScript (app, name, mount, prefix) {
var desc = app._manifest;
if (! desc) {
throw new Error("Invalid application manifest, app " + arangodb.inspect(app));
}
@ -527,6 +532,7 @@ function executeAppScript (app, name, mount, prefix) {
appContext.isDevelopment = devel;
appContext.isProduction = ! devel;
appContext.manifest = app._manifest;
extendContext(appContext, app, root);
@ -557,10 +563,10 @@ function teardownApp (app, mount, prefix) {
function upsertAalAppEntry (manifest, thumbnail, path) {
var aal = getStorage();
var doc = aal.firstExample({
type: "app",
name: manifest.name,
version: manifest.version
var doc = aal.firstExample({
type: "app",
name: manifest.name,
version: manifest.version
});
if (doc === null) {
@ -610,7 +616,7 @@ function mountAalApp (app, mount, options) {
var find = aal.firstExample({ type: "mount", mount: mount, active: true });
if (find !== null) {
throw new Error("Cannot use mount path '" + mount + "', already used by '"
throw new Error("Cannot use mount path '" + mount + "', already used by '"
+ find.app + "' (" + find._key + ")");
}
@ -747,6 +753,8 @@ function routingAalApp (app, mount, options) {
appContextTempl.isDevelopment = devel;
appContextTempl.isProduction = ! devel;
appContextTempl.manifest = app._manifest;
var appContext;
var file;
@ -815,13 +823,13 @@ function routingAalApp (app, mount, options) {
for (j = 0; j < rt.length; ++j) {
route = rt[j];
if (route.hasOwnProperty("url")) {
route.url.match = arangodb.normalizeURL(p + "/" + route.url.match);
}
route.context = i;
routes[key].push(route);
}
}
@ -910,16 +918,16 @@ function scanDirectory (path) {
exports.scanAppDirectory = function () {
'use strict';
var aal = getStorage();
// remove all loaded apps first
aal.removeByExample({ type: "app" });
// now re-scan, starting with system apps
scanDirectory(module.systemAppPath());
scanDirectory(module.systemAppPath());
// now scan database-specific apps
scanDirectory(module.appPath());
scanDirectory(module.appPath());
};
////////////////////////////////////////////////////////////////////////////////
@ -1214,7 +1222,7 @@ exports.devSetup = function (filename) {
var root = module.devAppPath();
var m = fs.join(root, filename, "manifest.json");
if (fs.exists(m)) {
try {
var mf = JSON.parse(fs.read(m));
@ -1262,7 +1270,7 @@ exports.devTeardown = function (filename) {
var root = module.devAppPath();
var m = fs.join(root, filename, "manifest.json");
if (fs.exists(m)) {
try {
var mf = JSON.parse(fs.read(m));
@ -1296,7 +1304,7 @@ exports.devTeardown = function (filename) {
exports.appRoutes = function () {
'use strict';
var aal = getStorage();
return arangodb.db._executeTransaction({
@ -1327,7 +1335,7 @@ exports.appRoutes = function () {
var r = routingAalApp(app, mount, options);
if (r === null) {
throw new Error("Cannot compute the routing table for Foxx application '"
throw new Error("Cannot compute the routing table for Foxx application '"
+ app._id + "', check the log file for errors!");
}
@ -1367,7 +1375,7 @@ exports.developmentRoutes = function () {
if (fs.exists(m)) {
try {
var mf = JSON.parse(fs.read(m));
checkManifest(m, mf);
var appId = "dev:" + mf.name + ":" + files[j];
@ -1387,7 +1395,7 @@ exports.developmentRoutes = function () {
var r = routingAalApp(app, mount, options);
if (r === null) {
throw new Error("Cannot compute the routing table for Foxx application '"
throw new Error("Cannot compute the routing table for Foxx application '"
+ app._id + "', check the log file for errors!");
}

View File

@ -40,14 +40,46 @@ var RequestContext,
createBodyParamBubbleWrap,
addCheck;
createBodyParamBubbleWrap = function (handler, paramName, Proto) {
var elementExtractFactory = function(paramName, rootElement) {
var extractElement;
if (rootElement) {
extractElement = function (req) {
return req.body()[paramName];
};
} else {
extractElement = function (req) {
return req.body();
};
}
return extractElement;
};
var bubbleWrapFactory = function (handler, paramName, Proto, extractElement, multiple) {
'use strict';
if (multiple) {
Proto = Proto[0];
}
return function (req, res) {
req.parameters[paramName] = new Proto(req.body());
if (multiple) {
req.parameters[paramName] = _.map(extractElement(req), function (raw) {
return new Proto(raw);
});
} else {
req.parameters[paramName] = new Proto(extractElement(req));
}
handler(req, res);
};
};
createBodyParamBubbleWrap = function (handler, paramName, Proto, rootElement) {
'use strict';
var extractElement = elementExtractFactory(paramName, rootElement);
return bubbleWrapFactory(handler, paramName, Proto, extractElement, is.array(Proto));
};
createErrorBubbleWrap = function (handler, errorClass, code, reason, errorHandler) {
'use strict';
if (is.notExisty(errorHandler)) {
@ -137,14 +169,15 @@ extend(SwaggerDocs.prototype, {
/// Used for documenting and constraining the routes.
////////////////////////////////////////////////////////////////////////////////
RequestContext = function (executionBuffer, models, route) {
RequestContext = function (executionBuffer, models, route, rootElement) {
'use strict';
this.route = route;
this.typeToRegex = {
"int": "/[0-9]+/",
"integer": "/[0-9]+/",
"string": "/.+/"
"string": "/[^/]+/"
};
this.rootElement = rootElement;
this.docs = new SwaggerDocs(this.route.docs, models);
this.docs.addNickname(route.docs.httpMethod, route.url.match);
@ -249,14 +282,30 @@ extend(RequestContext.prototype, {
/// This will initialize a `Model` with the data and provide it to you via the
/// params as `paramName`.
/// For information about how to annotate your models, see the Model section.
/// If you provide the Model in an array, the response will take multiple models
/// instead of one.
///
/// If you wrap the provided model in an array, the body param is always an array
/// and accordingly the return value of the `params` for the body call will also
/// return an array of models.
///
/// The behavior of `bodyParam` changes depending on the `rootElement` option
/// set in the manifest. If it is set to true, it is expected that the body is an
/// object with a key of the same name as the `paramName` argument.
/// The value of this object is either a single object or in the case of a multi
/// element an array of objects.
////////////////////////////////////////////////////////////////////////////////
bodyParam: function (paramName, description, Proto) {
'use strict';
var handler = this.route.action.callback;
this.docs.addBodyParam(paramName, description, Proto.toJSONSchema(paramName));
this.route.action.callback = createBodyParamBubbleWrap(handler, paramName, Proto);
if (is.array(Proto)) {
this.docs.addBodyParam(paramName, description, Proto[0].toJSONSchema(paramName));
} else {
this.docs.addBodyParam(paramName, description, Proto.toJSONSchema(paramName));
}
this.route.action.callback = createBodyParamBubbleWrap(handler, paramName, Proto, this.rootElement);
return this;
},

View File

@ -3,7 +3,9 @@ require("internal").flushModuleCache();
var jsunity = require("jsunity"),
FoxxController = require("org/arangodb/foxx").Controller,
db = require("org/arangodb").db,
_ = require("underscore"),
fakeContext,
fakeContextWithRootElement,
stub_and_mock = require("org/arangodb/stub_and_mock"),
stub = stub_and_mock.stub,
allow = stub_and_mock.allow,
@ -13,6 +15,21 @@ fakeContext = {
prefix: "",
foxxes: [],
comments: [],
manifest: {
rootElement: false
},
clearComments: function () {},
comment: function () {},
collectionName: function () {}
};
fakeContextWithRootElement = {
prefix: "",
foxxes: [],
comments: [],
manifest: {
rootElement: true
},
clearComments: function () {},
comment: function () {},
collectionName: function () {}
@ -283,7 +300,7 @@ function DocumentationAndConstraintsSpec () {
assertEqual(routes.length, 1);
assertEqual(routes[0].url.constraint.foxx, "/.+/");
assertEqual(routes[0].url.constraint.foxx, "/[^/]+/");
assertEqual(routes[0].docs.parameters[0].paramType, "path");
assertEqual(routes[0].docs.parameters[0].name, "foxx");
assertEqual(routes[0].docs.parameters[0].description, "Kind of Foxx");
@ -309,7 +326,7 @@ function DocumentationAndConstraintsSpec () {
assertEqual(routes.length, 1);
assertEqual(routes[0].url.constraint.foxxParam, "/.+/");
assertEqual(routes[0].url.constraint.foxxParam, "/[^/]+/");
assertEqual(routes[0].docs.parameters[0].paramType, "path");
assertEqual(routes[0].docs.parameters[0].name, "foxxParam");
assertEqual(routes[0].docs.parameters[0].description, "Kind of Foxx");
@ -362,6 +379,27 @@ function DocumentationAndConstraintsSpec () {
assertEqual(routes[0].docs.parameters[0].dataType, jsonSchema.id);
},
testAddBodyParamWithMultipleItems: function () {
var paramName = stub(),
description = stub(),
ModelPrototype = stub(),
jsonSchema = { id: 'a', required: [], properties: {} };
allow(ModelPrototype)
.toReceive("toJSONSchema")
.andReturn(jsonSchema);
app.get('/foxx', function () {
//nothing
}).bodyParam(paramName, description, [ModelPrototype]);
assertEqual(routes.length, 1);
assertEqual(routes[0].docs.parameters[0].name, paramName);
assertEqual(routes[0].docs.parameters[0].paramType, "body");
assertEqual(routes[0].docs.parameters[0].description, description);
assertEqual(routes[0].docs.parameters[0].dataType, jsonSchema.id);
},
testDefineBodyParamAddsJSONSchemaToModels: function () {
var paramName = stub(),
description = stub(),
@ -406,6 +444,34 @@ function DocumentationAndConstraintsSpec () {
ModelPrototype.assertIsSatisfied();
},
testSetParamForBodyParamWithMultipleItems: function () {
var req = { parameters: {} },
res = {},
paramName = stub(),
description = stub(),
rawElement = stub(),
requestBody = [rawElement],
ModelPrototype = stub(),
jsonSchemaId = stub(),
called = false;
allow(req)
.toReceive("body")
.andReturn(requestBody);
ModelPrototype = mockConstructor(rawElement);
ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
app.get('/foxx', function (providedReq) {
called = (providedReq.parameters[paramName][0] instanceof ModelPrototype);
}).bodyParam(paramName, description, [ModelPrototype]);
routes[0].action.callback(req, res);
assertTrue(called);
ModelPrototype.assertIsSatisfied();
},
testDocumentationForErrorResponse: function () {
var CustomErrorClass = function () {};
@ -639,36 +705,6 @@ function CommentDrivenDocumentationSpec () {
};
}
function HelperFunctionSpec () {
var app;
return {
setUp: function () {
fakeContext.collectionPrefix = "fancy";
app = new FoxxController(fakeContext);
},
testGetACollection: function () {
db._create("fancy_pants");
assertEqual(app.collection("pants"), db._collection("fancy_pants"));
},
testGetACollectionThatDoesNotExist: function () {
var err;
db._drop("fancy_pants");
try {
app.collection("pants");
} catch(e) {
err = e;
}
assertEqual(err.message, "collection with name 'fancy_pants' does not exist.");
}
};
}
function SetupAuthorization () {
var app;
@ -767,12 +803,79 @@ function SetupAuthorization () {
};
}
function FoxxControllerWithRootElement () {
var app;
return {
setUp: function () {
app = new FoxxController(fakeContextWithRootElement);
routes = app.routingInfo.routes;
},
testBodyParamWithOneElement: function () {
var req = { parameters: {} },
res = {},
paramName = 'myBodyParam',
description = stub(),
rawElement = stub(),
requestBody = { myBodyParam: rawElement },
ModelPrototype = stub(),
jsonSchemaId = stub(),
called = false;
allow(req)
.toReceive("body")
.andReturn(requestBody);
ModelPrototype = mockConstructor(rawElement);
ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
app.get('/foxx', function (providedReq) {
called = (providedReq.parameters[paramName] instanceof ModelPrototype);
}).bodyParam(paramName, description, ModelPrototype);
routes[0].action.callback(req, res);
assertTrue(called);
ModelPrototype.assertIsSatisfied();
},
testBodyParamWithMultipleElement: function () {
var req = { parameters: {} },
res = {},
paramName = 'myBodyParam',
description = stub(),
rawElement = stub(),
requestBody = { myBodyParam: [rawElement] },
ModelPrototype = stub(),
jsonSchemaId = stub(),
called = false;
allow(req)
.toReceive("body")
.andReturn(requestBody);
ModelPrototype = mockConstructor(rawElement);
ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
app.get('/foxx', function (providedReq) {
called = (providedReq.parameters[paramName][0] instanceof ModelPrototype);
}).bodyParam(paramName, description, [ModelPrototype]);
routes[0].action.callback(req, res);
assertTrue(called);
ModelPrototype.assertIsSatisfied();
}
};
}
jsunity.run(CreateFoxxControllerSpec);
jsunity.run(SetRoutesFoxxControllerSpec);
jsunity.run(DocumentationAndConstraintsSpec);
jsunity.run(AddMiddlewareFoxxControllerSpec);
jsunity.run(CommentDrivenDocumentationSpec);
jsunity.run(HelperFunctionSpec);
jsunity.run(SetupAuthorization);
jsunity.run(FoxxControllerWithRootElement);
return jsunity.done();

View File

@ -129,6 +129,7 @@ ERROR_ARANGO_INDEX_CREATION_FAILED,1235,"index creation failed","Will be raised
################################################################################
ERROR_ARANGO_DATAFILE_FULL,1300,"datafile full","Will be raised when the datafile reaches its limit."
ERROR_ARANGO_EMPTY_DATADIR,1301,"server database directory is empty","Will be raised when encoutering an empty server database directory."
################################################################################
## ArangoDB replication errors
@ -289,6 +290,15 @@ ERROR_GRAPH_COULD_NOT_CREATE_EDGE,1907,"could not create edge","Will be raised w
ERROR_GRAPH_COULD_NOT_CHANGE_EDGE,1908,"could not change edge","Will be raised when the edge could not be changed."
ERROR_GRAPH_TOO_MANY_ITERATIONS,1909,"too many iterations","Will be raised when too many iterations are done in a graph traversal."
ERROR_GRAPH_INVALID_FILTER_RESULT,1910,"invalid filter result","Will be raised when an invalid filter result is returned in a graph traversal."
ERROR_GRAPH_COLLECTION_MULTI_USE,1920,"multi use of edge collection in edge def","an edge collection may only be used once in one edge definition of a graph.",
ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS,1921,"edge collection already used in edge def"," is already used by another graph in a different edge definition.",
ERROR_GRAPH_CREATE_MISSING_NAME,1922,"missing graph name","a graph name is required to create a graph.",
ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION,1923,"malformed edge def","the edge definition is malformed. It has to be an array of objects.",
ERROR_GRAPH_NOT_FOUND,1924,"graph not found","a graph with this name could not be found.",
ERROR_GRAPH_DUPLICATE,1925,"graph already exists","a graph with this name already exists.",
ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST,1926,"collection does not exist"," does not exist.",
ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX,1927,"not a vertex collection","the collection is not a vertex collection.",
ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION,1928,"not in orphan collection","Vertex collection not in orphan collection of the graph.",
################################################################################
## Session errors

View File

@ -100,6 +100,7 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_ARANGO_INDEX_DOCUMENT_ATTRIBUTE_MISSING, "index insertion warning - attribute missing in document");
REG_ERROR(ERROR_ARANGO_INDEX_CREATION_FAILED, "index creation failed");
REG_ERROR(ERROR_ARANGO_DATAFILE_FULL, "datafile full");
REG_ERROR(ERROR_ARANGO_EMPTY_DATADIR, "server database directory is empty");
REG_ERROR(ERROR_REPLICATION_NO_RESPONSE, "no response");
REG_ERROR(ERROR_REPLICATION_INVALID_RESPONSE, "invalid response");
REG_ERROR(ERROR_REPLICATION_MASTER_ERROR, "master error");
@ -205,6 +206,15 @@ void TRI_InitialiseErrorMessages (void) {
REG_ERROR(ERROR_GRAPH_COULD_NOT_CHANGE_EDGE, "could not change edge");
REG_ERROR(ERROR_GRAPH_TOO_MANY_ITERATIONS, "too many iterations");
REG_ERROR(ERROR_GRAPH_INVALID_FILTER_RESULT, "invalid filter result");
REG_ERROR(ERROR_GRAPH_COLLECTION_MULTI_USE, "multi use of edge collection in edge def");
REG_ERROR(ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS, "edge collection already used in edge def");
REG_ERROR(ERROR_GRAPH_CREATE_MISSING_NAME, "missing graph name");
REG_ERROR(ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION, "malformed edge def");
REG_ERROR(ERROR_GRAPH_NOT_FOUND, "graph not found");
REG_ERROR(ERROR_GRAPH_DUPLICATE, "graph already exists");
REG_ERROR(ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST, "collection does not exist");
REG_ERROR(ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX, "not a vertex collection");
REG_ERROR(ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION, "not in orphan collection");
REG_ERROR(ERROR_SESSION_UNKNOWN, "unknown session");
REG_ERROR(ERROR_SESSION_EXPIRED, "session expired");
REG_ERROR(SIMPLE_CLIENT_UNKNOWN_ERROR, "unknown client error");

View File

@ -213,6 +213,8 @@ extern "C" {
/// Will be raised when an attempt to create an index has failed.
/// - 1300: @LIT{datafile full}
/// Will be raised when the datafile reaches its limit.
/// - 1301: @LIT{server database directory is empty}
/// Will be raised when encoutering an empty server database directory.
/// - 1400: @LIT{no response}
/// Will be raised when the replication applier does not receive any or an
/// incomplete response from the master.
@ -485,6 +487,25 @@ extern "C" {
/// - 1910: @LIT{invalid filter result}
/// Will be raised when an invalid filter result is returned in a graph
/// traversal.
/// - 1920: @LIT{multi use of edge collection in edge def}
/// an edge collection may only be used once in one edge definition of a
/// graph.
/// - 1921: @LIT{edge collection already used in edge def}
/// is already used by another graph in a different edge definition.
/// - 1922: @LIT{missing graph name}
/// a graph name is required to create a graph.
/// - 1923: @LIT{malformed edge def}
/// the edge definition is malformed. It has to be an array of objects.
/// - 1924: @LIT{graph not found}
/// a graph with this name could not be found.
/// - 1925: @LIT{graph already exists}
/// a graph with this name already exists.
/// - 1926: @LIT{collection does not exist}
/// does not exist.
/// - 1927: @LIT{not a vertex collection}
/// the collection is not a vertex collection.
/// - 1928: @LIT{not in orphan collection}
/// Vertex collection not in orphan collection of the graph.
/// - 1950: @LIT{unknown session}
/// Will be raised when an invalid/unknown session id is passed to the server.
/// - 1951: @LIT{session expired}
@ -1452,6 +1473,16 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_ARANGO_DATAFILE_FULL (1300)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1301: ERROR_ARANGO_EMPTY_DATADIR
///
/// server database directory is empty
///
/// Will be raised when encoutering an empty server database directory.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_ARANGO_EMPTY_DATADIR (1301)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1400: ERROR_REPLICATION_NO_RESPONSE
///
@ -2557,6 +2588,96 @@ void TRI_InitialiseErrorMessages (void);
#define TRI_ERROR_GRAPH_INVALID_FILTER_RESULT (1910)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1920: ERROR_GRAPH_COLLECTION_MULTI_USE
///
/// multi use of edge collection in edge def
///
/// an edge collection may only be used once in one edge definition of a graph.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_COLLECTION_MULTI_USE (1920)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1921: ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS
///
/// edge collection already used in edge def
///
/// is already used by another graph in a different edge definition.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_COLLECTION_USE_IN_MULTI_GRAPHS (1921)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1922: ERROR_GRAPH_CREATE_MISSING_NAME
///
/// missing graph name
///
/// a graph name is required to create a graph.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_CREATE_MISSING_NAME (1922)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1923: ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION
///
/// malformed edge def
///
/// the edge definition is malformed. It has to be an array of objects.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_CREATE_MALFORMED_EDGE_DEFINITION (1923)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1924: ERROR_GRAPH_NOT_FOUND
///
/// graph not found
///
/// a graph with this name could not be found.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_NOT_FOUND (1924)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1925: ERROR_GRAPH_DUPLICATE
///
/// graph already exists
///
/// a graph with this name already exists.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_DUPLICATE (1925)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1926: ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST
///
/// collection does not exist
///
/// does not exist.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST (1926)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1927: ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX
///
/// not a vertex collection
///
/// the collection is not a vertex collection.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX (1927)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1928: ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION
///
/// not in orphan collection
///
/// Vertex collection not in orphan collection of the graph.
////////////////////////////////////////////////////////////////////////////////
#define TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION (1928)
////////////////////////////////////////////////////////////////////////////////
/// @brief 1950: ERROR_SESSION_UNKNOWN
///