From ae872007aca9e24cfcf180c4798c046aa76944fd Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 7 Nov 2013 14:06:44 +0100 Subject: [PATCH 01/27] updated database creation API --- UnitTests/HttpInterface/api-database-spec.rb | 107 +++++++++++++++++- arangod/V8Server/ApplicationV8.cpp | 4 + arangod/V8Server/v8-vocbase.cpp | 39 ++++++- js/actions/api-database.js | 99 +++++++++++++++- .../modules/org/arangodb/arango-database.js | 5 +- .../frontend/js/templates/foxxActiveView.ejs | 2 +- .../js/templates/foxxInstalledView.ejs | 2 +- .../modules/org/arangodb/arango-database.js | 5 +- js/common/tests/shell-database.js | 90 ++++++++++++++- js/server/version-check.js | 12 +- 10 files changed, 348 insertions(+), 17 deletions(-) diff --git a/UnitTests/HttpInterface/api-database-spec.rb b/UnitTests/HttpInterface/api-database-spec.rb index bd3119ec43..aa6332b292 100644 --- a/UnitTests/HttpInterface/api-database-spec.rb +++ b/UnitTests/HttpInterface/api-database-spec.rb @@ -125,7 +125,6 @@ describe ArangoDB do response = doc.parsed_response response["error"].should eq(true) response["errorNum"].should eq(1207) - end it "drops an existing database" do @@ -189,6 +188,13 @@ describe ArangoDB do result["path"].should be_kind_of(String) result["isSystem"].should eq(false) + # retrieve user for new database + doc = ArangoDB.log_get("#{prefix}-create-current", "/_db/#{name}/_api/user/root") + doc.code.should eq(200) + result = doc.parsed_response + result["user"].should eq("root") + result["active"].should eq(true) + doc = ArangoDB.log_delete("#{prefix}-create-current", api + "/#{name}") doc.code.should eq(200) response = doc.parsed_response @@ -196,6 +202,105 @@ describe ArangoDB do response["error"].should eq(false) end + it "creates a new database with two users" do + body = "{\"name\" : \"#{name}\", \"users\": [ { \"username\": \"admin\", \"password\": \"secret\", \"extra\": { \"gender\": \"m\" } }, { \"username\": \"foxx\", \"active\": false } ] }" + doc = ArangoDB.log_post("#{prefix}-create-users", api, :body => body) + + doc.code.should eq(200) + doc.headers['content-type'].should eq("application/json; charset=utf-8") + response = doc.parsed_response + response["result"].should eq(true) + response["error"].should eq(false) + + # list of databases should include the new database + doc = ArangoDB.log_get("#{prefix}-create-users", api) + doc.code.should eq(200) + result = doc.parsed_response["result"] + + result.should include("_system") + result.should include(name) + + # retrieve information about new database + doc = ArangoDB.log_get("#{prefix}-create-users", "/_db/#{name}" + api + "/current") + doc.code.should eq(200) + result = doc.parsed_response["result"] + result["name"].should eq(name) + result["path"].should be_kind_of(String) + result["isSystem"].should eq(false) + + # retrieve information about user "admin" + doc = ArangoDB.log_get("#{prefix}-create-users", "/_db/#{name}/_api/user/admin") + doc.code.should eq(200) + result = doc.parsed_response + result["user"].should eq("admin") + result["active"].should eq(true) + result["extra"]["gender"].should eq("m") + + # retrieve information about user "foxx" + doc = ArangoDB.log_get("#{prefix}-create-users", "/_db/#{name}/_api/user/foxx") + doc.code.should eq(200) + result = doc.parsed_response + result["user"].should eq("foxx") + result["active"].should eq(false) + + # retrieve information about user "root" + doc = ArangoDB.log_get("#{prefix}-create-users", "/_db/#{name}/_api/user/root") + doc.code.should eq(404) + + doc = ArangoDB.log_delete("#{prefix}-create-users", api + "/#{name}") + doc.code.should eq(200) + response = doc.parsed_response + response["result"].should eq(true) + response["error"].should eq(false) + end + + it "creates a new database with an invalid user object" do + body = "{\"name\" : \"#{name}\", \"users\": [ { } ] }" + doc = ArangoDB.log_post("#{prefix}-create-users-missing", api, :body => body) + + doc.code.should eq(400) + doc.headers['content-type'].should eq("application/json; charset=utf-8") + response = doc.parsed_response + response["error"].should eq(true) + end + + it "creates a new database with an invalid user" do + body = "{\"name\" : \"#{name}\", \"users\": [ { \"username\": \"\" } ] }" + doc = ArangoDB.log_post("#{prefix}-create-users-invalid", api, :body => body) + + doc.code.should eq(200) + doc.headers['content-type'].should eq("application/json; charset=utf-8") + response = doc.parsed_response + response["result"].should eq(true) + response["error"].should eq(false) + + # list of databases should include the new database + doc = ArangoDB.log_get("#{prefix}-create-users-invalid", api) + doc.code.should eq(200) + result = doc.parsed_response["result"] + + result.should include("_system") + result.should include(name) + + # retrieve information about new database + doc = ArangoDB.log_get("#{prefix}-create-users-invalid", "/_db/#{name}" + api + "/current") + doc.code.should eq(200) + result = doc.parsed_response["result"] + result["name"].should eq(name) + result["path"].should be_kind_of(String) + result["isSystem"].should eq(false) + + # retrieve information about user "root" + doc = ArangoDB.log_get("#{prefix}-create-users-invalid", "/_db/#{name}/_api/user/root") + doc.code.should eq(404) + + doc = ArangoDB.log_delete("#{prefix}-create-users-invalid", api + "/#{name}") + doc.code.should eq(200) + response = doc.parsed_response + response["result"].should eq(true) + response["error"].should eq(false) + end + it "checks _system database restrictions" do body = "{\"name\" : \"#{name}\" }" doc = ArangoDB.log_post("#{prefix}-check-system", api, :body => body) diff --git a/arangod/V8Server/ApplicationV8.cpp b/arangod/V8Server/ApplicationV8.cpp index 3c1eac8654..c55ebf03cc 100644 --- a/arangod/V8Server/ApplicationV8.cpp +++ b/arangod/V8Server/ApplicationV8.cpp @@ -797,6 +797,10 @@ bool ApplicationV8::prepareV8Instance (const size_t i) { if (vocbase != 0) { // special check script to be run just once in first thread (not in all) // but for all databases + v8::HandleScope scope; + + context->_context->Global()->Set(v8::String::New("UPGRADE_ARGS"), v8::Object::New()); + bool ok = TRI_V8RunVersionCheck(vocbase, &_startupLoader, context->_context); if (! ok) { diff --git a/arangod/V8Server/v8-vocbase.cpp b/arangod/V8Server/v8-vocbase.cpp index 99efab1352..b6997a2486 100644 --- a/arangod/V8Server/v8-vocbase.cpp +++ b/arangod/V8Server/v8-vocbase.cpp @@ -7918,24 +7918,44 @@ static v8::Handle JS_ListDatabases (v8::Arguments const& argv) { //////////////////////////////////////////////////////////////////////////////// /// @brief create a new database /// -/// @FUN{@FA{db}._createDatabase(@FA{name})} +/// @FUN{@FA{db}._createDatabase(@FA{name}, @FA{options}, @FA{users})} /// /// Creates a new database with the name specified by @FA{name}. -/// There are restrictions for database names (see @ref DatabaseNames}. +/// There are restrictions for database names (see @ref DatabaseNames). /// /// Note that even if the database is created successfully, there will be no /// change into the current database to the new database. Changing the current /// database must explicitly be requested by using the @ref HandlingDatabasesUse /// "db._useDatabase" method. /// +/// The optional @FA{users} attribute can be used to create initial users for +/// the new database. If specified, it must be a list of user objects. Each user +/// object can contain the following attributes: +/// +/// - `username`: the user name as a string. This attribute is mandatory. +/// +/// - `passwd`: the user password as a string. If not specified, then it defaults +/// to the empty string. +/// +/// - `active`: a boolean flag indicating whether the user accout should be +/// actived or not. The default value is `true`. +/// +/// - `extra`: an optional JSON object with extra user information. The data +/// contained in `extra` will be stored for the user but not be interpreted +/// further by ArangoDB. +/// +/// If no initial users are specified, a default user `root` will be created +/// with an empty string password. This ensures that the new database will be +/// accessible via HTTP after it is created. +/// /// This method can only be used from within the `_system` database. //////////////////////////////////////////////////////////////////////////////// static v8::Handle JS_CreateDatabase (v8::Arguments const& argv) { v8::HandleScope scope; - if (argv.Length() < 1) { - TRI_V8_EXCEPTION_USAGE(scope, "db._createDatabase(, )"); + if (argv.Length() < 1 || argv.Length() > 3) { + TRI_V8_EXCEPTION_USAGE(scope, "db._createDatabase(, , )"); } TRI_vocbase_t* vocbase = GetContextVocBase(); @@ -8011,6 +8031,17 @@ static v8::Handle JS_CreateDatabase (v8::Arguments const& argv) { assert(database != 0); + // copy users into context + if (argv.Length() >= 3 && argv[2]->IsArray()) { + v8::Handle users = v8::Object::New(); + users->Set(v8::String::New("users"), argv[2]); + + v8::Context::GetCurrent()->Global()->Set(v8::String::New("UPGRADE_ARGS"), users); + } + else { + v8::Context::GetCurrent()->Global()->Set(v8::String::New("UPGRADE_ARGS"), v8::Object::New()); + } + if (TRI_V8RunVersionCheck(database, (JSLoader*) v8g->_loader, v8::Context::GetCurrent())) { // version check ok TRI_V8InitialiseFoxx(database, v8::Context::GetCurrent()); diff --git a/js/actions/api-database.js b/js/actions/api-database.js index 031b01ed48..59c722f185 100644 --- a/js/actions/api-database.js +++ b/js/actions/api-database.js @@ -212,7 +212,27 @@ function get_api_database (req, res) { /// Creates a new database /// /// The request body must be a JSON object with the attribute `name`. `name` must -/// contain a valid @ref DatabaseNames. +/// contain a valid @ref DatabaseNames "database name". +/// +/// The request body can optionally contain an attribute `users`, which then +/// must be a list of user objects to initially create for the new database. +/// Each user object can contain the following attributes: +/// +/// - `username`: the user name as a string. This attribute is mandatory. +/// +/// - `passwd`: the user password as a string. If not specified, then it defaults +/// to the empty string. +/// +/// - `active`: a boolean flag indicating whether the user accout should be +/// actived or not. The default value is `true`. +/// +/// - `extra`: an optional JSON object with extra user information. The data +/// contained in `extra` will be stored for the user but not be interpreted +/// further by ArangoDB. +/// +/// If `users` is not specified or does not contain any users, a default user +/// `root` will be created with an empty string password. This ensures that the +/// new database will be accessible after it is created. /// /// The response is a JSON object with the attribute `result` set to `true`. /// @@ -230,8 +250,13 @@ function get_api_database (req, res) { /// @RESTRETURNCODE{403} /// is returned if the request was not executed in the `_system` database. /// +/// @RESTRETURNCODE{409} +/// is returned if a database with the specified name already exists. +/// /// @EXAMPLES /// +/// Creating a database named `example`. +/// /// @EXAMPLE_ARANGOSH_RUN{RestDatabaseCreate} /// var url = "/_api/database"; /// var name = "example"; @@ -251,6 +276,40 @@ function get_api_database (req, res) { /// /// logJsonResponse(response); /// @END_EXAMPLE_ARANGOSH_RUN +/// +/// Creating a database named `mydb` with two users. +/// +/// @EXAMPLE_ARANGOSH_RUN{RestDatabaseCreateUsers} +/// var url = "/_api/database"; +/// var name = "mydb"; +/// try { +/// db._dropDatabase(name); +/// } +/// catch (err) { +/// } +/// +/// var data = { +/// name: name, +/// users: [ +/// { +/// username : "admin", +/// passwd : "secret", +/// active: true +/// }, +/// { +/// username : "tester", +/// passwd : "test001", +/// active: false +/// } +/// ] +/// }; +/// var response = logCurlRequest('POST', url, JSON.stringify(data)); +/// +/// db._dropDatabase(name); +/// assert(response.code === 200); +/// +/// logJsonResponse(response); +/// @END_EXAMPLE_ARANGOSH_RUN //////////////////////////////////////////////////////////////////////////////// function post_api_database (req, res) { @@ -277,7 +336,43 @@ function post_api_database (req, res) { return; } - var result = arangodb.db._createDatabase(json.name || "", options); + var users = json.users; + + if (users === undefined) { + users = [ ]; + } + else if (! Array.isArray(users)) { + actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER); + return; + } + + var i; + for (i = 0; i < users.length; ++i) { + var user = users[i]; + if (typeof user !== 'object' || + ! user.hasOwnProperty('username') || + typeof(user.username) !== 'string') { + // bad username + actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER); + return; + } + + if (! user.hasOwnProperty('passwd')) { + // default to empty string + users[i].passwd = ''; + } + else if (typeof(user.passwd) !== 'string') { + // bad password type + actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER); + return; + } + + if (! user.hasOwnProperty('active')) { + users[i].active = true; + } + } + + var result = arangodb.db._createDatabase(json.name || "", options, users); actions.resultOk(req, res, actions.HTTP_OK, { result : result }); } diff --git a/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-database.js b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-database.js index bc66a71171..ce602a7db0 100644 --- a/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-database.js +++ b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-database.js @@ -823,10 +823,11 @@ ArangoDatabase.prototype._query = function (query, bindVars, cursorOptions, opti /// @brief create a new database //////////////////////////////////////////////////////////////////////////////// -ArangoDatabase.prototype._createDatabase = function (name, options) { +ArangoDatabase.prototype._createDatabase = function (name, options, users) { var data = { name: name, - options: options || { } + options: options || { }, + users: users || [ ] }; var requestResult = this._connection.POST("/_api/database", JSON.stringify(data)); diff --git a/js/apps/system/aardvark/frontend/js/templates/foxxActiveView.ejs b/js/apps/system/aardvark/frontend/js/templates/foxxActiveView.ejs index 30be51f9a3..38be092ab6 100644 --- a/js/apps/system/aardvark/frontend/js/templates/foxxActiveView.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/foxxActiveView.ejs @@ -5,7 +5,7 @@
- icon + icon

Mount: <%=attributes.mount %>
diff --git a/js/apps/system/aardvark/frontend/js/templates/foxxInstalledView.ejs b/js/apps/system/aardvark/frontend/js/templates/foxxInstalledView.ejs index 04e620d3b8..597d60c03d 100644 --- a/js/apps/system/aardvark/frontend/js/templates/foxxInstalledView.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/foxxInstalledView.ejs @@ -1,7 +1,7 @@

<%= attributes.name %><%= attributes.isSystem ? " (system)" : "" %>
- icon + icon

Path: <%=attributes.path %>
diff --git a/js/client/modules/org/arangodb/arango-database.js b/js/client/modules/org/arangodb/arango-database.js index c429290b8b..f9b28d8fa0 100644 --- a/js/client/modules/org/arangodb/arango-database.js +++ b/js/client/modules/org/arangodb/arango-database.js @@ -822,10 +822,11 @@ ArangoDatabase.prototype._query = function (query, bindVars, cursorOptions, opti /// @brief create a new database //////////////////////////////////////////////////////////////////////////////// -ArangoDatabase.prototype._createDatabase = function (name, options) { +ArangoDatabase.prototype._createDatabase = function (name, options, users) { var data = { name: name, - options: options || { } + options: options || { }, + users: users || [ ] }; var requestResult = this._connection.POST("/_api/database", JSON.stringify(data)); diff --git a/js/common/tests/shell-database.js b/js/common/tests/shell-database.js index 5ec4e19b12..739f4c2fc9 100644 --- a/js/common/tests/shell-database.js +++ b/js/common/tests/shell-database.js @@ -211,6 +211,94 @@ function DatabaseSuite () { assertTrue(internal.db._dropDatabase("UnitTestsDatabase1")); }, +//////////////////////////////////////////////////////////////////////////////// +/// @brief test _createDatabase function +//////////////////////////////////////////////////////////////////////////////// + + testCreateDatabaseWithUsers1 : function () { + assertEqual("_system", internal.db._name()); + + try { + internal.db._dropDatabase("UnitTestsDatabase0"); + } + catch (err1) { + } + + // empty users + assertTrue(internal.db._createDatabase("UnitTestsDatabase0", { }, [ ])); + + assertTrue(internal.db._dropDatabase("UnitTestsDatabase0")); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test _createDatabase function +//////////////////////////////////////////////////////////////////////////////// + + testCreateDatabaseWithUsers2 : function () { + assertEqual("_system", internal.db._name()); + + try { + internal.db._dropDatabase("UnitTestsDatabase0"); + } + catch (err1) { + } + + var users = [ + { username: "admin", passwd: "secret", extra: { gender: "m" } }, + { username: "foo", active: false, extra: { gender: "f" } } + ]; + + assertTrue(internal.db._createDatabase("UnitTestsDatabase0", { }, users)); + + internal.db._useDatabase("UnitTestsDatabase0"); + var m = require("org/arangodb/users"); + var user = m.document("admin"); + + assertEqual("admin", user.user); + assertTrue(user.active); + assertEqual("m", user.extra.gender); + + user = m.document("foo"); + assertEqual("foo", user.user); + assertFalse(user.active); + assertEqual("f", user.extra.gender); + + internal.db._useDatabase("_system"); + + assertTrue(internal.db._dropDatabase("UnitTestsDatabase0")); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test _createDatabase function +//////////////////////////////////////////////////////////////////////////////// + + testCreateDatabaseWithUsers3 : function () { + assertEqual("_system", internal.db._name()); + + try { + internal.db._dropDatabase("UnitTestsDatabase0"); + } + catch (err1) { + } + + var users = [ + { username: "admin", passwd: "secret", active: true, extra: { gender: "m" } }, + { username: "admin", passwd: "", active: false, extra: { gender: "m" } }, + ]; + assertTrue(internal.db._createDatabase("UnitTestsDatabase0", { }, users)); + + internal.db._useDatabase("UnitTestsDatabase0"); + var m = require("org/arangodb/users"); + var user = m.document("admin"); + assertEqual("admin", user.user); + assertTrue(user.active); + assertEqual("m", user.extra.gender); + + internal.db._useDatabase("_system"); + + assertTrue(internal.db._dropDatabase("UnitTestsDatabase0")); + }, + //////////////////////////////////////////////////////////////////////////////// /// @brief test _createDatabase function //////////////////////////////////////////////////////////////////////////////// @@ -298,7 +386,7 @@ function DatabaseSuite () { /// @brief test _createDatabase function //////////////////////////////////////////////////////////////////////////////// - testCreateDatabaseCase : function () { + testCreateDatabaseCaseSensitivity : function () { assertEqual("_system", internal.db._name()); var getCollections = function () { diff --git a/js/server/version-check.js b/js/server/version-check.js index c81c212969..01680b2be3 100644 --- a/js/server/version-check.js +++ b/js/server/version-check.js @@ -1,5 +1,5 @@ /*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, stupid: true, continue: true, regexp: true */ -/*global require, exports, module */ +/*global require, exports, module, UPGRADE_ARGS */ //////////////////////////////////////////////////////////////////////////////// /// @brief version check at the start of the server, will optionally perform @@ -42,7 +42,7 @@ /// @brief updates the database //////////////////////////////////////////////////////////////////////////////// -(function() { +(function(args) { var internal = require("internal"); var fs = require("fs"); var console = require("console"); @@ -285,6 +285,12 @@ return false; } + if (args && args.users) { + args.users.forEach(function(user) { + userManager.save(user.username, user.passwd, user.active, user.extra || { }); + }); + } + if (users.count() === 0) { // only add account if user has not created his/her own accounts already userManager.save("root", "", true); @@ -668,7 +674,7 @@ // we should never get here return true; -}()); +}(UPGRADE_ARGS)); //////////////////////////////////////////////////////////////////////////////// /// @} From 29aee6a6d5794ab9ca74af1ab95245ab9f01a1da Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Thu, 7 Nov 2013 13:15:01 +0000 Subject: [PATCH 02/27] strip files --- CMakeLists.txt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cbb3adb9f..f3fd614a60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -343,12 +343,13 @@ add_subdirectory(UnitTests) ## --SECTION-- PACKAGES ## ----------------------------------------------------------------------------- -set(CPACK_SET_DESTDIR ON) - ################################################################################ ### @brief general information ################################################################################ +set(CPACK_SET_DESTDIR ON) + + if (BUILD_PACKAGE STREQUAL "dmg-cli") set(CPACK_PACKAGE_NAME "ArangoDB-CLI") elseif (BUILD_PACKAGE STREQUAL "raspbian") @@ -362,6 +363,9 @@ set(CPACK_PACKAGE_VENDOR "triAGENS GmbH") set(CPACK_PACKAGE_CONTACT "info@arangodb.org") set(CPACK_PACKAGE_VERSION "${ARANGODB_VERSION}") + +set(CPACK_STRIP_FILES "ON") + ################################################################################ ### @brief MacOSX bundle ################################################################################ From e01973360972d9fa056ac4f12b3a18cd08e0218e Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Thu, 7 Nov 2013 14:23:07 +0000 Subject: [PATCH 03/27] used uid and gid --- Installation/Debian/rc.arangodb | 16 ++++++++++++++-- Installation/Linux/rc.arangod.Centos | 16 ++++++++++++++-- Installation/Linux/rc.arangod.OpenSuSE | 18 +++++++++++++++--- Installation/Linux/rc.arangod.Ubuntu | 16 ++++++++++++++-- arangod/CMakeLists.txt | 7 ++++++- 5 files changed, 63 insertions(+), 10 deletions(-) diff --git a/Installation/Debian/rc.arangodb b/Installation/Debian/rc.arangodb index eb529cb101..fd27e3ab2b 100755 --- a/Installation/Debian/rc.arangodb +++ b/Installation/Debian/rc.arangodb @@ -18,13 +18,25 @@ DESC="arango database server" NAME="arangod" PIDDIR=/var/run/arangodb PIDFILE=/var/run/arangodb/arangod.pid -CONF=/etc/arangodb/arangod.conf +CONF=/etc/arangodb/arangod-uid.conf test -x $DAEMON || exit 0 start () { test -d $PIDDIR || mkdir $PIDDIR - chown arangodb $PIDDIR + chown arangodb:arangodb $PIDDIR + + if test -d /var/log/arangodb; then + chown -R arangodb:arangodb /var/log/arangodb + fi + + if test -d /var/lib/arangodb; then + chown -R arangodb:arangodb /var/lib/arangodb + fi + + if test -d /var/lib/arangodb-apps; then + chown -R arangodb:arangodb /var/lib/arangodb-apps + fi if [ "$1" = "--upgrade" ]; then $DAEMON -c $CONF $@ diff --git a/Installation/Linux/rc.arangod.Centos b/Installation/Linux/rc.arangod.Centos index 64f2d76d43..ab4a4a3fd5 100644 --- a/Installation/Linux/rc.arangod.Centos +++ b/Installation/Linux/rc.arangod.Centos @@ -14,7 +14,7 @@ ARANGO_BIN=/usr/sbin/arangod test -x $ARANGO_BIN || exit 5 -ARANGO_SYSCONFIG=/etc/arangodb/arangod.conf +ARANGO_SYSCONFIG=/etc/arangodb/arangod-uid.conf test -r $ARANGO_SYSCONFIG || exit 6 pidfile=/var/run/arangodb/arangod.pid @@ -27,7 +27,19 @@ start() { echo -n $"Starting $ARANGO_BIN: " ARANGO_PIDDIR=`dirname $pidfile` - test -d $ARANGO_PIDDIR || (mkdir $ARANGO_PIDDIR && chown arangodb $ARANGO_PIDDIR) + test -d $ARANGO_PIDDIR || (mkdir $ARANGO_PIDDIR && chown arangodb:arangodb $ARANGO_PIDDIR) + + if test -d /var/log/arangodb; then + chown -R arangodb:arangodb /var/log/arangodb + fi + + if test -d /var/lib/arangodb; then + chown -R arangodb:arangodb /var/lib/arangodb + fi + + if test -d /var/lib/arangodb-apps; then + chown -R arangodb:arangodb /var/lib/arangodb-apps + fi if [ "$1" = "--upgrade" ]; then $ARANGO_BIN -c $ARANGO_SYSCONFIG $@ diff --git a/Installation/Linux/rc.arangod.OpenSuSE b/Installation/Linux/rc.arangod.OpenSuSE index 28e72f209f..440f6bed17 100644 --- a/Installation/Linux/rc.arangod.OpenSuSE +++ b/Installation/Linux/rc.arangod.OpenSuSE @@ -22,7 +22,7 @@ ARANGO_BIN=/usr/sbin/arangod test -x $ARANGO_BIN || exit 5 -ARANGO_SYSCONFIG=/etc/arangodb/arangod.conf +ARANGO_SYSCONFIG=/etc/arangodb/arangod-uid.conf test -r $ARANGO_SYSCONFIG || exit 6 @@ -45,8 +45,20 @@ rc_reset start () { ARANGO_PIDDIR=`dirname $ARANGO_PIDFILE` - test -d $ARANGO_PIDDIR || (mkdir $ARANGO_PIDDIR && chown arangodb $ARANGO_PIDDIR) - + test -d $ARANGO_PIDDIR || (mkdir $ARANGO_PIDDIR && chown arangodb:arangodb $ARANGO_PIDDIR) + + if test -d /var/log/arangodb; then + chown -R arangodb:arangodb /var/log/arangodb + fi + + if test -d /var/lib/arangodb; then + chown -R arangodb:arangodb /var/lib/arangodb + fi + + if test -d /var/lib/arangodb-apps; then + chown -R arangodb:arangodb /var/lib/arangodb-apps + fi + if [ "$1" = "--upgrade" ]; then $ARANGO_BIN -c $ARANGO_SYSCONFIG $@ else diff --git a/Installation/Linux/rc.arangod.Ubuntu b/Installation/Linux/rc.arangod.Ubuntu index 18dcce1588..8a21405f54 100644 --- a/Installation/Linux/rc.arangod.Ubuntu +++ b/Installation/Linux/rc.arangod.Ubuntu @@ -19,13 +19,25 @@ DESC="ArangoDB" NAME="arangod" PIDDIR=/var/run/arangodb PIDFILE=${PIDDIR}/arangod.pid -CONF=/etc/arangodb/arangod.conf +CONF=/etc/arangodb/arangod-uid.conf test -x $DAEMON || exit 0 start () { test -d $PIDDIR || mkdir $PIDDIR - chown arangodb $PIDDIR + chown arangodb:arangodb $PIDDIR + + if test -d /var/log/arangodb; then + chown -R arangodb:arangodb /var/log/arangodb + fi + + if test -d /var/lib/arangodb; then + chown -R arangodb:arangodb /var/lib/arangodb + fi + + if test -d /var/lib/arangodb-apps; then + chown -R arangodb:arangodb /var/lib/arangodb-apps + fi if [ "$1" = "--upgrade" ]; then $DAEMON -c $CONF $@ diff --git a/arangod/CMakeLists.txt b/arangod/CMakeLists.txt index 94fd1dbc79..9a1457672e 100644 --- a/arangod/CMakeLists.txt +++ b/arangod/CMakeLists.txt @@ -158,9 +158,14 @@ endif () if (BUILD_PACKAGE STREQUAL "raspbian") install( - FILES ${PROJECT_SOURCE_DIR}/etc/arangodb/arangod-uid-arm.conf + FILES ${PROJECT_SOURCE_DIR}/etc/arangodb/arangod-arm.conf DESTINATION ${ETCDIR_NATIVE} RENAME arangod.conf) + + install( + FILES ${PROJECT_SOURCE_DIR}/etc/arangodb/arangod-uid-arm.conf + DESTINATION ${ETCDIR_NATIVE} + RENAME arangod-uid.conf) else () install( FILES ${PROJECT_SOURCE_DIR}/etc/arangodb/arangod.conf From 0273b1af7aa0925d3ade650e712f764044c3614b Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Thu, 7 Nov 2013 15:36:14 +0100 Subject: [PATCH 04/27] switch to -uid config --- etc/systemd/arangodb.service | 2 +- js/actions/api-system.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/etc/systemd/arangodb.service b/etc/systemd/arangodb.service index d4201e0d80..41244e76f5 100644 --- a/etc/systemd/arangodb.service +++ b/etc/systemd/arangodb.service @@ -20,7 +20,7 @@ After=syslog.target network.target Type=forking PIDFile=/var/run/arangodb/arangod.pid ExecStartPre=/usr/bin/install -g arangodb -o arangodb -d /var/run/arangodb -ExecStart=/usr/sbin/arangod -c /etc/arangodb/arangod.conf --pid-file /var/run/arangodb/arangod.pid --supervisor --uid arangodb +ExecStart=/usr/sbin/arangod -c /etc/arangodb/arangod-uid.conf --pid-file /var/run/arangodb/arangod.pid --supervisor [Install] WantedBy=multi-user.target diff --git a/js/actions/api-system.js b/js/actions/api-system.js index 60996342f8..603f7488fb 100644 --- a/js/actions/api-system.js +++ b/js/actions/api-system.js @@ -310,6 +310,37 @@ actions.defineHttp({ } }); +//////////////////////////////////////////////////////////////////////////////// +/// @fn JSF_get_admin_echo_database_name +/// @brief returns the database name +/// +/// @RESTHEADER{GET /_admin/database_name,returns the database name} +/// +/// @RESTDESCRIPTION +/// +/// The call returns an object with the following attributes: +/// +/// - `name`: the name of the database +/// +/// @RESTRETURNCODES +/// +/// @RESTRETURNCODE{200} +/// Name was returned successfully. +/// +//////////////////////////////////////////////////////////////////////////////// + +actions.defineHttp({ + url : "_admin/database-name", + context : "admin", + prefix : true, + + callback : function (req, res) { + res.responseCode = actions.HTTP_OK; + res.contentType = "application/json; charset=utf-8"; + res.body = JSON.stringify({ name: internal.db._name() }); + } +}); + //////////////////////////////////////////////////////////////////////////////// /// @fn JSF_get_admin_statistics /// @brief returns system status information for the server From 9d5e5ff7ccfc499e66246f5e0ba1de1cd1560893 Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 7 Nov 2013 16:26:45 +0100 Subject: [PATCH 05/27] merged fix for issue #653 --- UnitTests/Makefile.unittests | 1 + arangod/Ahuacatl/ahuacatl-access-optimiser.c | 13 +- arangod/Ahuacatl/ahuacatl-codegen.c | 64 ++- arangod/Ahuacatl/ahuacatl-index.c | 4 +- .../tests/ahuacatl-queries-optimiser-in.js | 426 ++++++++++++++++++ 5 files changed, 493 insertions(+), 15 deletions(-) create mode 100644 js/server/tests/ahuacatl-queries-optimiser-in.js diff --git a/UnitTests/Makefile.unittests b/UnitTests/Makefile.unittests index 6232cc3b6d..072ebc2dab 100755 --- a/UnitTests/Makefile.unittests +++ b/UnitTests/Makefile.unittests @@ -380,6 +380,7 @@ unittests-shell-server-only: SHELL_SERVER_AHUACATL = @top_srcdir@/js/server/tests/ahuacatl-ranges.js \ @top_srcdir@/js/server/tests/ahuacatl-queries-optimiser.js \ + @top_srcdir@/js/server/tests/ahuacatl-queries-optimiser-in.js \ @top_srcdir@/js/server/tests/ahuacatl-queries-optimiser-limit.js \ @top_srcdir@/js/server/tests/ahuacatl-queries-optimiser-sort.js \ @top_srcdir@/js/server/tests/ahuacatl-queries-optimiser-ref.js \ diff --git a/arangod/Ahuacatl/ahuacatl-access-optimiser.c b/arangod/Ahuacatl/ahuacatl-access-optimiser.c index e4d9d4414b..53e38f83df 100644 --- a/arangod/Ahuacatl/ahuacatl-access-optimiser.c +++ b/arangod/Ahuacatl/ahuacatl-access-optimiser.c @@ -2216,6 +2216,7 @@ static TRI_aql_field_access_t* CreateAccessForNode (TRI_aql_context_t* const con // all other operation types require a value... value = TRI_NodeJsonAql(context, node); + if (value == NULL) { TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); @@ -2302,6 +2303,7 @@ static TRI_aql_field_access_t* GetAttributeAccess (TRI_aql_context_t* const cont } fieldAccess = CreateAccessForNode(context, field, operator, node); + if (fieldAccess == NULL) { // OOM TRI_SetErrorContextAql(context, TRI_ERROR_OUT_OF_MEMORY, NULL); @@ -2459,7 +2461,7 @@ static TRI_vector_pointer_t* ProcessNode (TRI_aql_context_t* const context, return result; } - + if (node->_type == TRI_AQL_NODE_OPERATOR_BINARY_EQ || node->_type == TRI_AQL_NODE_OPERATOR_BINARY_NE || node->_type == TRI_AQL_NODE_OPERATOR_BINARY_LT || @@ -2475,12 +2477,13 @@ static TRI_vector_pointer_t* ProcessNode (TRI_aql_context_t* const context, TRI_aql_node_t* node2; TRI_aql_node_type_e operator; bool useBoth; - + +/* if (node->_type == TRI_AQL_NODE_OPERATOR_BINARY_IN && rhs->_type != TRI_AQL_NODE_LIST) { // in operator is special. if right operand is not a list, we must abort here return NULL; } - +*/ useBoth = false; if ((lhs->_type == TRI_AQL_NODE_REFERENCE || lhs->_type == TRI_AQL_NODE_ATTRIBUTE_ACCESS || lhs->_type == TRI_AQL_NODE_FCALL) && @@ -2523,7 +2526,7 @@ static TRI_vector_pointer_t* ProcessNode (TRI_aql_context_t* const context, else { return NULL; } - + if (node2->_type != TRI_AQL_NODE_VALUE && node2->_type != TRI_AQL_NODE_LIST && node2->_type != TRI_AQL_NODE_ARRAY && @@ -2567,7 +2570,7 @@ again: } } - if (useBoth) { + if (useBoth && node->_type != TRI_AQL_NODE_OPERATOR_BINARY_IN) { // in this situation, we have an expression of type a.x == b.y // we'll have to process both sides of the expression TRI_aql_node_t* tempNode; diff --git a/arangod/Ahuacatl/ahuacatl-codegen.c b/arangod/Ahuacatl/ahuacatl-codegen.c index 1662cc3901..b7c65c54ed 100644 --- a/arangod/Ahuacatl/ahuacatl-codegen.c +++ b/arangod/Ahuacatl/ahuacatl-codegen.c @@ -1168,9 +1168,11 @@ static void GeneratePrimaryAccess (TRI_aql_codegen_js_t* const generator, assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT || fieldAccess->_type == TRI_AQL_ACCESS_LIST || (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE && - fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ)); + (fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN))); - if (fieldAccess->_type == TRI_AQL_ACCESS_LIST) { + if (fieldAccess->_type == TRI_AQL_ACCESS_LIST || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN) { ScopeOutput(generator, "aql.GET_DOCUMENTS_PRIMARY_LIST('"); } else { @@ -1182,7 +1184,8 @@ static void GeneratePrimaryAccess (TRI_aql_codegen_js_t* const generator, ScopeOutputIndexId(generator, collectionName, idx); ScopeOutput(generator, ", "); if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE) { - assert(fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ); + assert(fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN); if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); @@ -1226,6 +1229,26 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator, ScopeOutput(generator, ")"); return; } + + if (fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN) { + ScopeOutput(generator, "aql.GET_DOCUMENTS_HASH_LIST('"); + ScopeOutput(generator, collectionName); + ScopeOutput(generator, "', "); + ScopeOutputIndexId(generator, collectionName, idx); + ScopeOutput(generator, ", "); + ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1); + ScopeOutput(generator, ", "); + + if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { + ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); + } + else { + ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node); + } + ScopeOutput(generator, ")"); + return; + } + // fall through to exact access } @@ -1241,7 +1264,8 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator, assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT || (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE && - fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ)); + (fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN))); if (i > 0) { ScopeOutput(generator, ", "); @@ -1250,7 +1274,8 @@ static void GenerateHashAccess (TRI_aql_codegen_js_t* const generator, ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1); ScopeOutput(generator, " : "); if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE) { - assert(fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ); + assert(fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN); if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); @@ -1286,9 +1311,11 @@ static void GenerateEdgeAccess (TRI_aql_codegen_js_t* const generator, assert(fieldAccess->_type == TRI_AQL_ACCESS_EXACT || fieldAccess->_type == TRI_AQL_ACCESS_LIST || (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE && - fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ)); + (fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN))); - if (fieldAccess->_type == TRI_AQL_ACCESS_LIST) { + if (fieldAccess->_type == TRI_AQL_ACCESS_LIST || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN) { ScopeOutput(generator, "aql.GET_DOCUMENTS_EDGE_LIST('"); } else { @@ -1300,7 +1327,8 @@ static void GenerateEdgeAccess (TRI_aql_codegen_js_t* const generator, ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1); ScopeOutput(generator, ", "); if (fieldAccess->_type == TRI_AQL_ACCESS_REFERENCE) { - assert(fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ); + assert(fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN); if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); @@ -1345,6 +1373,25 @@ static void GenerateSkiplistAccess (TRI_aql_codegen_js_t* const generator, ScopeOutput(generator, ")"); return; } + + if (fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN) { + ScopeOutput(generator, "aql.GET_DOCUMENTS_SKIPLIST_LIST('"); + ScopeOutput(generator, collectionName); + ScopeOutput(generator, "', "); + ScopeOutputIndexId(generator, collectionName, idx); + ScopeOutput(generator, ", "); + ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1); + ScopeOutput(generator, ", "); + if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { + ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); + } + else { + ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node); + } + ScopeOutput(generator, ")"); + return; + } + // fall through to other access types } @@ -1473,7 +1520,6 @@ static void GenerateBitarrayAccess (TRI_aql_codegen_js_t* const generator, ScopeOutput(generator, " : "); switch (fieldAccess->_type) { - case TRI_AQL_ACCESS_EXACT: { ScopeOutputJson(generator, fieldAccess->_value._value); break; diff --git a/arangod/Ahuacatl/ahuacatl-index.c b/arangod/Ahuacatl/ahuacatl-index.c index 347b789c4e..bb83c4ffb5 100644 --- a/arangod/Ahuacatl/ahuacatl-index.c +++ b/arangod/Ahuacatl/ahuacatl-index.c @@ -90,7 +90,8 @@ static bool IsExactCandidate (const TRI_aql_field_access_t* const candidate) { } if (candidate->_type == TRI_AQL_ACCESS_REFERENCE && - candidate->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ) { + (candidate->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_EQ || + candidate->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN)) { // == ref return true; } @@ -349,6 +350,7 @@ TRI_aql_index_t* TRI_DetermineIndexAql (TRI_aql_context_t* const context, size_t k; indexedFieldName = idx->_fields._buffer[j]; + if (indexedFieldName == NULL) { continue; } diff --git a/js/server/tests/ahuacatl-queries-optimiser-in.js b/js/server/tests/ahuacatl-queries-optimiser-in.js new file mode 100644 index 0000000000..0dc1da4dce --- /dev/null +++ b/js/server/tests/ahuacatl-queries-optimiser-in.js @@ -0,0 +1,426 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief tests for query language, in +/// +/// @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 Jan Steemann +/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +var jsunity = require("jsunity"); +var internal = require("internal"); +var helper = require("org/arangodb/aql-helper"); +var getQueryResults = helper.getQueryResults; +var getQueryExplanation = helper.getQueryExplanation; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test suite +//////////////////////////////////////////////////////////////////////////////// + +function ahuacatlQueryOptimiserInTestSuite () { + var c = null; + var cn = "UnitTestsAhuacatlOptimiserIn"; + + return { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief set up +//////////////////////////////////////////////////////////////////////////////// + + setUp : function () { + internal.db._drop(cn); + c = internal.db._create(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief tear down +//////////////////////////////////////////////////////////////////////////////// + + tearDown : function () { + internal.db._drop(cn); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInMergeOr : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + + var expected = [ 'test1', 'test2', 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c._key IN parents || c._key IN [ 'test1' ] || c._key IN [ 'test2' ] || c._key IN parents SORT c._key RETURN c._key"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInMergeAnd : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c._key IN parents && c._key IN [ 'test5', 'test7' ] && c._key IN [ 'test7', 'test5' ] && c._key IN parents SORT c._key RETURN c._key"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInPrimaryConst : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c._key IN parents SORT c._key RETURN c._key"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c._key IN parents SORT c._key RETURN c._key"); + assertEqual("index", explain[1].expression.extra.accessType); + assertEqual("primary", explain[1].expression.extra.index.type); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInPrimaryDynamic : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = (FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] RETURN c._key) FOR c IN " + cn + " FILTER c._key IN parents SORT c._key RETURN c._key"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = (FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] RETURN c._key) FOR c IN " + cn + " FILTER c._key IN parents SORT c._key RETURN c._key"); + assertEqual("index", explain[5].expression.extra.accessType); + assertEqual("primary", explain[5].expression.extra.index.type); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInPrimaryDynamicRef : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + + var expected = [ { keys: [ 'test4' ] }, { keys: [ 'test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] SORT c._key RETURN { keys: (FOR c2 IN " + cn + " FILTER c2._key IN [ c.parent ] RETURN c2._key) }"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInPrimaryRef : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + + var expected = [ { keys: [ 'test4' ] }, { keys: [ 'test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] SORT c._key RETURN { keys: (FOR c2 IN " + cn + " FILTER c2._key IN c.parents SORT c2._key RETURN c2._key) }"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInHashConst : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueConstraint("code"); + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual("index", explain[1].expression.extra.accessType); + assertEqual("hash", explain[1].expression.extra.index.type); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInHashDynamic : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueConstraint("code"); + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = (FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] RETURN c.code) FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = (FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] RETURN c.code) FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual("index", explain[5].expression.extra.accessType); + assertEqual("hash", explain[5].expression.extra.index.type); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInHashDynamicRef : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueConstraint("code"); + + var expected = [ { keys: [ 'test4' ] }, { keys: [ 'test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] SORT c.code RETURN { keys: (FOR c2 IN " + cn + " FILTER c2.code IN [ c.parent ] RETURN c2.code) }"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInHashRef : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueConstraint("code"); + + var expected = [ { keys: [ 'test4' ] }, { keys: [ 'test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] SORT c.code RETURN { keys: (FOR c2 IN " + cn + " FILTER c2.code IN c.parents SORT c2.code RETURN c2.code) }"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInSkipConst : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueSkiplist("code"); + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = [ 'test5', 'test7' ] FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual("index", explain[1].expression.extra.accessType); + assertEqual("skiplist", explain[1].expression.extra.index.type); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInSkipDynamic : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueSkiplist("code"); + + var expected = [ 'test5', 'test7' ]; + var actual = getQueryResults("LET parents = (FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] RETURN c.code) FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = (FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] RETURN c.code) FOR c IN " + cn + " FILTER c.code IN parents SORT c.code RETURN c.code"); + assertEqual("index", explain[5].expression.extra.accessType); + assertEqual("skiplist", explain[5].expression.extra.index.type); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInSkipDynamicRef : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueSkiplist("code"); + + var expected = [ { keys: [ 'test4' ] }, { keys: [ 'test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] SORT c.code RETURN { keys: (FOR c2 IN " + cn + " FILTER c2.code IN [ c.parent ] RETURN c2.code) }"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInSkipRef : function () { + c.save({ code: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ code: "test" + i, parent: "test" + (i - 1), parents: [ "test" + (i - 1) ] }); + } + c.ensureUniqueSkiplist("code"); + + var expected = [ { keys: [ 'test4' ] }, { keys: [ 'test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c.code IN [ 'test5', 'test7' ] SORT c.code RETURN { keys: (FOR c2 IN " + cn + " FILTER c2.code IN c.parents SORT c2.code RETURN c2.code) }"); + assertEqual(expected, actual); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInEdgeConst : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i }); + } + + var en = cn + "Edge"; + internal.db._drop(en); + var e = internal.db._createEdgeCollection(en); + + for (var i = 1; i < 100; ++i) { + e.save(cn + "/test" + i, cn + "/test" + (i - 1), { }); + } + + var expected = [ cn + '/test4', cn + '/test6' ]; + var actual = getQueryResults("LET parents = [ '" + cn + "/test5', '" + cn + "/test7' ] FOR c IN " + en + " FILTER c._from IN parents SORT c._to RETURN c._to"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = [ '" + cn + "/test5', '" + cn + "/test7' ] FOR c IN " + en + " FILTER c._from IN parents SORT c._to RETURN c._to"); + assertEqual("index", explain[1].expression.extra.accessType); + assertEqual("edge", explain[1].expression.extra.index.type); + + internal.db._drop(en); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInEdgeDynamic : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i }); + } + + var en = cn + "Edge"; + internal.db._drop(en); + var e = internal.db._createEdgeCollection(en); + + for (var i = 1; i < 100; ++i) { + e.save(cn + "/test" + i, cn + "/test" + (i - 1), { }); + } + + var expected = [ cn + '/test4', cn + '/test6' ]; + var actual = getQueryResults("LET parents = (FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] RETURN c._id) FOR c IN " + en + " FILTER c._from IN parents SORT c._to RETURN c._to"); + assertEqual(expected, actual); + + var explain = getQueryExplanation("LET parents = (FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] RETURN c._id) FOR c IN " + en + " FILTER c._from IN parents SORT c._to RETURN c._to"); + assertEqual("index", explain[5].expression.extra.accessType); + assertEqual("edge", explain[5].expression.extra.index.type); + + internal.db._drop(en); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInEdgeDynamicRef : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i }); + } + + var en = cn + "Edge"; + internal.db._drop(en); + var e = internal.db._createEdgeCollection(en); + + for (var i = 1; i < 100; ++i) { + e.save(cn + "/test" + i, cn + "/test" + (i - 1), { }); + } + + var expected = [ { keys: [ cn + '/test4' ] }, { keys: [ cn + '/test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] SORT c._key RETURN { keys: (FOR c2 IN " + en + " FILTER c2._from IN [ c._id ] RETURN c2._to) }"); + assertEqual(expected, actual); + + internal.db._drop(en); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testInEdgeRef : function () { + c.save({ _key: "test0" }); + for (var i = 1; i < 100; ++i) { + c.save({ _key: "test" + i, ids: [ cn + "/test" + i ] }); + } + + var en = cn + "Edge"; + internal.db._drop(en); + var e = internal.db._createEdgeCollection(en); + + for (var i = 1; i < 100; ++i) { + e.save(cn + "/test" + i, cn + "/test" + (i - 1), { }); + } + + var expected = [ { keys: [ cn + '/test4' ] }, { keys: [ cn + '/test6' ] } ]; + var actual = getQueryResults("FOR c IN " + cn + " FILTER c._key IN [ 'test5', 'test7' ] SORT c._key RETURN { keys: (FOR c2 IN " + en + " FILTER c2._from IN c.ids RETURN c2._to) }"); + assertEqual(expected, actual); + + internal.db._drop(en); + } + + }; + +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief executes the test suite +//////////////////////////////////////////////////////////////////////////////// + +jsunity.run(ahuacatlQueryOptimiserInTestSuite); + +return jsunity.done(); + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)" +// End: From 40a21d0efb8ca7b03d8465f86773369c0dd52b4a Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 7 Nov 2013 16:24:57 +0100 Subject: [PATCH 06/27] fixed bitarray index access --- arangod/Ahuacatl/ahuacatl-codegen.c | 25 ++++++++++++++++++- .../tests/ahuacatl-queries-optimiser-in.js | 18 +++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/arangod/Ahuacatl/ahuacatl-codegen.c b/arangod/Ahuacatl/ahuacatl-codegen.c index b7c65c54ed..8ad46ab05d 100644 --- a/arangod/Ahuacatl/ahuacatl-codegen.c +++ b/arangod/Ahuacatl/ahuacatl-codegen.c @@ -1494,6 +1494,24 @@ static void GenerateBitarrayAccess (TRI_aql_codegen_js_t* const generator, ScopeOutput(generator, ")"); return; } + + if (fieldAccess->_value._reference._operator == TRI_AQL_NODE_OPERATOR_BINARY_IN) { + ScopeOutput(generator, "aql.GET_DOCUMENTS_BITARRAY_LIST('"); + ScopeOutput(generator, collectionName); + ScopeOutput(generator, "', "); + ScopeOutputIndexId(generator, collectionName, idx); + ScopeOutput(generator, ", "); + ScopeOutputQuoted2(generator, fieldAccess->_fullName + fieldAccess->_variableNameLength + 1); + ScopeOutput(generator, ", "); + if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { + ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); + } + else { + ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node); + } + ScopeOutput(generator, ")"); + return; + } // fall through to other access types } @@ -1526,7 +1544,12 @@ static void GenerateBitarrayAccess (TRI_aql_codegen_js_t* const generator, } case TRI_AQL_ACCESS_REFERENCE: { - ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node); + if (fieldAccess->_value._reference._type == TRI_AQL_REFERENCE_VARIABLE) { + ScopeOutputRegister(generator, LookupSymbol(generator, fieldAccess->_value._reference._ref._name)); + } + else { + ProcessAttributeAccess(generator, fieldAccess->_value._reference._ref._node); + } break; } diff --git a/js/server/tests/ahuacatl-queries-optimiser-in.js b/js/server/tests/ahuacatl-queries-optimiser-in.js index 0dc1da4dce..0f22927133 100644 --- a/js/server/tests/ahuacatl-queries-optimiser-in.js +++ b/js/server/tests/ahuacatl-queries-optimiser-in.js @@ -406,6 +406,24 @@ function ahuacatlQueryOptimiserInTestSuite () { assertEqual(expected, actual); internal.db._drop(en); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief check a ref access without any indexes +//////////////////////////////////////////////////////////////////////////////// + + testBitarray : function () { + var colors = [ "black", "blue", "green", "red" ]; + var expected = []; + + for (var i = 0; i < 100; ++i) { + c.save({ value: colors[i % 4] }); + expected.push(colors[Math.floor(i / 25)]); + } + c.ensureBitarray("value", colors); + + var actual = getQueryResults("LET colors = UNIQUE((FOR x IN @@cn RETURN x.value)) FOR x IN @@cn FILTER x.value IN colors SORT x.value RETURN x.value", { "@cn" : cn }); + assertEqual(expected, actual); } }; From 3c61100809a27f289466b47e8298657e7245dea7 Mon Sep 17 00:00:00 2001 From: Michael Hackstein Date: Thu, 7 Nov 2013 18:24:16 +0100 Subject: [PATCH 07/27] Fix for Database selection in Web Interface --- .../aardvark/frontend/css/dbSelectionView.css | 12 ++++ .../aardvark/frontend/css/navigationView.css | 2 +- .../aardvark/frontend/js/arango/arango.js | 39 +++++++++++++ .../js/collections/arangoDocuments.js | 4 +- .../js/graphViewer/ui/graphViewerUI.js | 8 +-- .../js/modules/org/arangodb/arangosh.js | 1 + .../aardvark/frontend/js/routers/router.js | 55 ++++++++++++++++++- .../frontend/js/templates/footerView.ejs | 15 ++++- .../frontend/js/templates/graphView.ejs | 20 +++++-- .../frontend/js/templates/navigationView.ejs | 4 +- .../frontend/js/views/collectionView.js | 4 +- .../frontend/js/views/collectionsView.js | 4 +- .../frontend/js/views/dbSelectionView.js | 38 +++++++++++++ .../aardvark/frontend/js/views/footerView.js | 50 ++++++++++++----- .../aardvark/frontend/js/views/graphView.js | 24 ++++++-- .../frontend/js/views/navigationView.js | 43 +++++---------- js/apps/system/aardvark/manifest.json | 3 + 17 files changed, 253 insertions(+), 73 deletions(-) create mode 100644 js/apps/system/aardvark/frontend/css/dbSelectionView.css create mode 100644 js/apps/system/aardvark/frontend/js/views/dbSelectionView.js diff --git a/js/apps/system/aardvark/frontend/css/dbSelectionView.css b/js/apps/system/aardvark/frontend/css/dbSelectionView.css new file mode 100644 index 0000000000..f4deadedb8 --- /dev/null +++ b/js/apps/system/aardvark/frontend/css/dbSelectionView.css @@ -0,0 +1,12 @@ +span.selectDB { + top: 6px; + left: 210px; + position: absolute; +} + +span.selectDB > select { + line-height: 20px; + height: 20px; + width: 150px; + padding: 0px; +} diff --git a/js/apps/system/aardvark/frontend/css/navigationView.css b/js/apps/system/aardvark/frontend/css/navigationView.css index c7dd94746a..97597d8d77 100644 --- a/js/apps/system/aardvark/frontend/css/navigationView.css +++ b/js/apps/system/aardvark/frontend/css/navigationView.css @@ -56,7 +56,7 @@ body, input, textarea, .page-title span, .pingback a.url { margin-right: 15px; } -@media (max-width: 1060px) { +@media (max-width: 1284px) { #arangoCollectionUl { display: none; } #collectionsDropdown ul { width: auto !important; } #arangoCollectionSelect { display: inline-block; } diff --git a/js/apps/system/aardvark/frontend/js/arango/arango.js b/js/apps/system/aardvark/frontend/js/arango/arango.js index b02508db01..6a1daecea2 100644 --- a/js/apps/system/aardvark/frontend/js/arango/arango.js +++ b/js/apps/system/aardvark/frontend/js/arango/arango.js @@ -26,6 +26,45 @@ window.arangoHelper = { }); }, + currentDatabase: function () { + var returnVal = false; + $.ajax({ + type: "GET", + cache: false, + url: "/_api/database/current", + contentType: "application/json", + processData: false, + async: false, + success: function(data) { + returnVal = data.result.name; + }, + error: function(data) { + returnVal = false; + } + }); + return returnVal; + }, + + databaseAllowed: function () { + var currentDB = this.currentDatabase(); + returnVal = false; + $.ajax({ + type: "GET", + cache: false, + url: "/_db/"+encodeURIComponent(currentDB)+"/_api/database/", + contentType: "application/json", + processData: false, + async: false, + success: function(data) { + returnVal = true; + }, + error: function(data) { + returnVal = false; + } + }); + return returnVal; + }, + removeNotifications: function () { $.gritter.removeAll(); this.lastNotificationMessage = null; diff --git a/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js b/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js index f3a2292909..03e1c9ac82 100644 --- a/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js +++ b/js/apps/system/aardvark/frontend/js/collections/arangoDocuments.js @@ -73,8 +73,8 @@ window.arangoDocuments = Backbone.Collection.extend({ if (this.documentsCount <= sortCount) { //sorted - myQueryVal = "FOR x in @@collection SORT TO_NUMBER(x._key) == 0 ? " + - "x._key : TO_NUMBER(x._key) LIMIT @offset, @count RETURN x"; + myQueryVal = "FOR x in @@collection SORT TO_NUMBER(x._key) == 0 " + + "? x._key : TO_NUMBER(x._key) LIMIT @offset, @count RETURN x"; } else { //not sorted diff --git a/js/apps/system/aardvark/frontend/js/graphViewer/ui/graphViewerUI.js b/js/apps/system/aardvark/frontend/js/graphViewer/ui/graphViewerUI.js index d282ef3d4a..00372f88b8 100644 --- a/js/apps/system/aardvark/frontend/js/graphViewer/ui/graphViewerUI.js +++ b/js/apps/system/aardvark/frontend/js/graphViewer/ui/graphViewerUI.js @@ -174,7 +174,6 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight, viewerConf var toolbox = document.createElement("div"), dispatcherUI = new EventDispatcherControls( toolbox, - //mousePointerBox, graphViewer.nodeShaper, graphViewer.edgeShaper, graphViewer.dispatcherConfig @@ -182,12 +181,9 @@ function GraphViewerUI(container, adapterConfig, optWidth, optHeight, viewerConf toolbox.id = "toolbox"; toolbox.className = "btn-group btn-group-vertical pull-left toolbox"; background.appendChild(toolbox); - /* - mousePointerBox.id = "mousepointer"; - mousePointerBox.className = "mousepointer"; - background.appendChild(mousePointerBox); - */ dispatcherUI.addAll(); + // Default selection + $("#control_event_expand").click(); }, updateAttributeExamples = function() { diff --git a/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js index 17ba357cac..786ab435a7 100644 --- a/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js +++ b/js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js @@ -152,6 +152,7 @@ exports.HELP = exports.createHelpHeadline("Help") + ' > db..exists(<_id>) check if document exists ' + "\n" + ' > db._query().toArray() execute an AQL query ' + "\n" + ' > db._useDatabase() switch database ' + "\n" + + ' > db._createDatabase() create a new database ' + "\n" + ' > db._listDatabases() list existing databases ' + "\n" + ' > help show help pages ' + "\n" + ' > exit ' + "\n" + diff --git a/js/apps/system/aardvark/frontend/js/routers/router.js b/js/apps/system/aardvark/frontend/js/routers/router.js index 56732bc070..66c811e672 100644 --- a/js/apps/system/aardvark/frontend/js/routers/router.js +++ b/js/apps/system/aardvark/frontend/js/routers/router.js @@ -1,5 +1,5 @@ /*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, newcap: true */ -/*global window, $, Backbone, document, arangoCollection, arangoHelper, dashboardView */ +/*global window, $, Backbone, document, arangoCollection,arangoHelper,dashboardView,arangoDatabase*/ $(document).ready(function() { @@ -19,6 +19,7 @@ $(document).ready(function() { "logs" : "logs", "about" : "about", "api" : "api", + "databases" : "databases", "application/installed/:key" : "applicationEdit", "application/available/:key" : "applicationInstall", "applications/installed" : "applicationsInstalled", @@ -31,6 +32,8 @@ $(document).ready(function() { initialize: function () { window.activeSession = new window.ArangoSession(); + window.arangoDatabase = new window.ArangoDatabase(); + window.arangoCollectionsStore = new window.arangoCollections(); window.arangoDocumentsStore = new window.arangoDocuments(); window.arangoDocumentStore = new window.arangoDocument(); @@ -74,6 +77,13 @@ $(document).ready(function() { this.graphView = new window.graphView({ collection: window.arangoCollectionsStore }); + + + var self = this; + $(window).resize(function() { + self.handleResize(); + }); + this.handleResize(); }, logsAllowed: function () { @@ -189,6 +199,24 @@ $(document).ready(function() { this.naviView.selectMenuItem('api-menu'); }, + databases: function() { + if (arangoHelper.databaseAllowed() === true) { + if (!this.databaseView) { + this.databaseView = new window.databaseView({ + collection: arangoDatabase + }); + } + this.databaseView.render(); + this.naviView.selectMenuItem('databases-menu'); + } + else { + window.App.navigate("#", {trigger: true}); + this.naviView.selectMenuItem('dashboard-menu'); + $('#databaseNavi').css('display','none'); + $('#databaseNaviSelect').css('display','none'); + } + }, + about: function() { if (!this.aboutView) { this.aboutView = new window.aboutView(); @@ -201,7 +229,7 @@ $(document).ready(function() { if (! this.logsAllowed()) { return; } - + var self = this; window.arangoLogsStore.fetch({ success: function () { @@ -225,7 +253,6 @@ $(document).ready(function() { } if (this.statistics === undefined) { this.statisticsCollection = new window.StatisticsCollection(); - //this.statisticsCollection.fetch(); } if (this.dashboardView === undefined) { this.dashboardView = new dashboardView({ @@ -328,12 +355,34 @@ $(document).ready(function() { var docuView = new window.AppDocumentationView({key: key}); docuView.render(); this.naviView.selectMenuItem('applications-menu'); + }, + + handleResize: function () { + var oldWidth = $('#content').width(); + var containerWidth = $(window).width() - 70; + /*var spanWidth = 242;*/ + var spanWidth = 243; + var divider = containerWidth / spanWidth; + var roundDiv = parseInt(divider, 10); + var newWidth = roundDiv*spanWidth -2; + var marginWidth = ((containerWidth+30) - newWidth)/2; + this.footerView.handleResize(marginWidth + 20); + this.naviView.handleResize(marginWidth); + $('#content').width(newWidth) + .css('margin-left', marginWidth) + .css('margin-right', marginWidth); + // $('.footer-right p').css('margin-right', marginWidth + 20); + // $('.footer-left p').css('margin-left', marginWidth + 20); + if (newWidth !== oldWidth && window.App) { + window.App.graphView.handleResize(newWidth); + } } }); window.App = new window.Router(); Backbone.history.start(); + window.App.handleResize(); }); diff --git a/js/apps/system/aardvark/frontend/js/templates/footerView.ejs b/js/apps/system/aardvark/frontend/js/templates/footerView.ejs index 0b59360037..4da97d2617 100644 --- a/js/apps/system/aardvark/frontend/js/templates/footerView.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/footerView.ejs @@ -1,8 +1,17 @@ - +<% + var n,v,db; + if (name) { + n = name || ""; + v = version || ""; + db = database || ""; + } +%>

- + diff --git a/js/apps/system/aardvark/frontend/js/templates/graphView.ejs b/js/apps/system/aardvark/frontend/js/templates/graphView.ejs index 784802781c..318239aa43 100644 --- a/js/apps/system/aardvark/frontend/js/templates/graphView.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/graphView.ejs @@ -94,7 +94,7 @@ gs = _.sortBy(gs, sortF);
- +
@@ -109,14 +109,24 @@ gs = _.sortBy(gs, sortF);
- +
- -
- + + +
diff --git a/js/apps/system/aardvark/frontend/js/templates/navigationView.ejs b/js/apps/system/aardvark/frontend/js/templates/navigationView.ejs index c066fc4e73..389837f820 100644 --- a/js/apps/system/aardvark/frontend/js/templates/navigationView.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/navigationView.ejs @@ -3,13 +3,14 @@
- +