diff --git a/Documentation/DbaManual/Authentication.md b/Documentation/DbaManual/Authentication.md index 12656c151a..db781a3509 100644 --- a/Documentation/DbaManual/Authentication.md +++ b/Documentation/DbaManual/Authentication.md @@ -17,9 +17,9 @@ fashion. The collection `_users` contains all users and a salted SHA256 hash of their passwords. A user can be active or inactive. A typical document of this collection is -@EXAMPLE_ARANGOSH_OUTPUT{AuthenticationExample1} - db._users.firstExample("user", "root") -@END_EXAMPLE_ARANGOSH_OUTPUT +@EXAMPLE_ARANGOSH_RUN{AuthenticationExample1} + log(db._users.firstExample("user", "root")); +@END_EXAMPLE_ARANGOSH_RUN Command-Line Options for the Authentication and Authorisation{#DbaManualAuthenticationCommandLine} -------------------------------------------------------------------------------------------------- diff --git a/Documentation/Scripts/generateExamples.py b/Documentation/Scripts/generateExamples.py index 6a8b07f534..609bc0b8b2 100644 --- a/Documentation/Scripts/generateExamples.py +++ b/Documentation/Scripts/generateExamples.py @@ -60,12 +60,18 @@ OutputDir = "/tmp/" ################################################################################ ### @brief arangosh output +### +### A list of commands that are executed in order to produce the output. The +### commands and there output is logged. ################################################################################ ArangoshOutput = {} ################################################################################ ### @brief arangosh run +### +### A list of commands that are executed in order to produce the output. This +### is mostly used for HTTP request examples. ################################################################################ ArangoshRun = {} @@ -150,7 +156,7 @@ for filename in argv: print >> sys.stderr, "%s\nduplicate file name '%s'\n%s\n" % ('#' * 80, name, '#' * 80) ArangoshFiles[name] = True - ArangoshOutput[name] = "" + ArangoshOutput[name] = [] state = STATE_ARANGOSH_OUTPUT continue @@ -179,7 +185,7 @@ for filename in argv: line = line[len(strip):] - ArangoshOutput[name] += line + "\n" + ArangoshOutput[name].append(line) elif state == STATE_ARANGOSH_RUN: m = r4.match(line) @@ -221,6 +227,8 @@ for filename in argv: ### @brief generate arangosh example ################################################################################ +gr1 = re.compile(r'^[ \n]*var ') + def generateArangoshOutput(): print "var internal = require('internal');" print "var fs = require('fs');" @@ -242,7 +250,21 @@ def generateArangoshOutput(): print "(function() {" print "internal.startCaptureMode();"; - print "try { var value = %s; print(value); } catch (err) { print(err); }" % value + print "try {" + print " var XXX;" + + for l in value: + m = gr1.match(l) + + print "print('arangosh> %s');" % l.replace("\\", "\\\\").replace("'", "\\'") + + if m: + print "%s" % l + else: + print "XXX = %s" % l + print "print(XXX);" + + print "} catch (err) { print(err); }" print "var output = internal.stopCaptureMode();"; print "ArangoshOutput['%s'] = output;" % key if JS_DEBUG: @@ -279,12 +301,13 @@ def generateArangoshRun(): print "internal.output('RUN STARTING: %s\\n');" % key print "var output = '';" print "var appender = function(text) { output += text; };" - print "var logCurlRequestRaw = require('internal').appendCurlRequest(appender);" + print "var log = function (a) { internal.startCaptureMode(); print(a); appender(internal.stopCaptureMode()); };" + print "var logCurlRequestRaw = internal.appendCurlRequest(appender);" print "var logCurlRequest = function () { var r = logCurlRequestRaw.apply(logCurlRequestRaw, arguments); db._collections(); return r; };" - print "var curlRequestRaw = require('internal').appendCurlRequest(function (text) { });" + print "var curlRequestRaw = internal.appendCurlRequest(function (text) {});" print "var curlRequest = function () { return curlRequestRaw.apply(curlRequestRaw, arguments); };" - print "var logJsonResponse = require('internal').appendJsonResponse(appender);" - print "var logRawResponse = require('internal').appendRawResponse(appender);" + print "var logJsonResponse = internal.appendJsonResponse(appender);" + print "var logRawResponse = internal.appendRawResponse(appender);" print "var assert = function(a) { if (! a) { internal.output('%s\\nASSERTION FAILED: %s\\n%s\\n'); throw new Error('assertion failed'); } };" % ('#' * 80, key, '#' * 80) print "try { %s internal.output('RUN SUCCEEDED: %s\\n'); } catch (err) { print('%s\\nRUN FAILED: %s, ', err, '\\n%s\\n'); }" % (value, key, '#' * 80, key, '#' * 80) print "ArangoshRun['%s'] = output;" % key diff --git a/Documentation/UserManual/HandlingDocuments.md b/Documentation/UserManual/HandlingDocuments.md index 19e07efd23..0d1ffb109f 100644 --- a/Documentation/UserManual/HandlingDocuments.md +++ b/Documentation/UserManual/HandlingDocuments.md @@ -15,9 +15,9 @@ corresponding language API. For example: -@EXAMPLE_ARANGOSH_OUTPUT{HandlingDocumentsExample1} - db.demo.document("demo/schlonz") -@END_EXAMPLE_ARANGOSH_OUTPUT +@EXAMPLE_ARANGOSH_RUN{HandlingDocumentsExample1} + log(db.demo.document("demo/schlonz")); +@END_EXAMPLE_ARANGOSH_RUN All documents contain special attributes: the document handle in `_id`, the document's unique key in `_key` and and the ETag aka document revision in diff --git a/js/common/modules/org/arangodb/general-graph.js b/js/common/modules/org/arangodb/general-graph.js index a69412f4ff..960fe1e04a 100644 --- a/js/common/modules/org/arangodb/general-graph.js +++ b/js/common/modules/org/arangodb/general-graph.js @@ -24,7 +24,7 @@ /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// -/// @author Florian Bartels +/// @author Florian Bartels, Michael Hackstein, Guido Schwab /// @author Copyright 2011-2014, triAGENS GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// @@ -123,7 +123,7 @@ var findOrCreateCollectionsByEdgeDefinitions = function (edgeDefinitions, noCrea /// @brief internal function to get graphs collection //////////////////////////////////////////////////////////////////////////////// -var _getGraphCollection = function() { +var getGraphCollection = function() { var gCol = db._graphs; if (gCol === null || gCol === undefined) { throw "_graphs collection does not exist."; @@ -178,10 +178,25 @@ var AQLGenerator = function(graph) { "graphName": graph.__name }; this.graph = graph; + this.cursor = null; this.lastEdgeVar = ""; }; +AQLGenerator.prototype._clearCursor = function() { + if (this.cursor) { + this.cursor.dispose(); + this.cursor = null; + } +}; + +AQLGenerator.prototype._createCursor = function() { + if (!this.cursor) { + this.cursor = this.execute(); + } +}; + AQLGenerator.prototype.edges = function(startVertex, direction) { + this._clearCursor(); var edgeName = "edges_" + this.stack.length; var query = "FOR " + edgeName + " IN GRAPH_EDGES(@graphName,@startVertex_" @@ -202,6 +217,7 @@ AQLGenerator.prototype.getLastEdgeVar = function() { }; AQLGenerator.prototype.restrict = function(restrictions) { + this._clearCursor(); var rest = stringToArray(restrictions); var unknown = []; var g = this.graph; @@ -229,6 +245,7 @@ AQLGenerator.prototype.restrict = function(restrictions) { }; AQLGenerator.prototype.filter = function(example) { + this._clearCursor(); var ex = []; if (Object.prototype.toString.call(example) !== "[object Array]") { if (Object.prototype.toString.call(example) !== "[object Object]") { @@ -268,14 +285,31 @@ AQLGenerator.prototype.printQuery = function() { }; AQLGenerator.prototype.execute = function() { + this._clearCursor(); var query = this.printQuery(); var bindVars = this.bindVars; query += " RETURN " + this.getLastEdgeVar(); - return db._query(query, bindVars); + return db._query(query, bindVars, {count: true}); }; AQLGenerator.prototype.toArray = function() { - return this.execute().toArray(); + this._createCursor(); + return this.cursor.toArray(); +}; + +AQLGenerator.prototype.count = function() { + this._createCursor(); + return this.cursor.count(); +}; + +AQLGenerator.prototype.hasNext = function() { + this._createCursor(); + return this.cursor.hasNext(); +}; + +AQLGenerator.prototype.next = function() { + this._createCursor(); + return this.cursor.next(); }; // ----------------------------------------------------------------------------- @@ -283,7 +317,32 @@ AQLGenerator.prototype.toArray = function() { // ----------------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////////////// +/// @fn JSF_general_graph_undirectedRelationDefinition /// @brief define an undirected relation. +/// +/// @FUN{general-graph._undirectedRelationDefinition(@FA{relationName}, @FA{vertexCollections})} +/// +/// Defines an undirected relation with the name @FA{relationName} using the +/// list of @FA{vertexCollections}. This relation allows the user to store +/// edges in any direction between any pair of vertices within the +/// @FA{vertexCollections}. +/// +/// @EXAMPLES +/// +/// To define simple relation with only one vertex collection: +/// +/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphUndirectedRelationDefinition1} +/// var graph = require("org/arangodb/general-graph"); +/// graph._undirectedRelationDefinition("friend", "user"); +/// @END_EXAMPLE_ARANGOSH_OUTPUT +/// +/// To define a relation between several vertex collections: +/// +/// @EXAMPLE_ARANGOSH_OUTPUT{generalGraphUndirectedRelationDefinition2} +/// var graph = require("org/arangodb/general-graph"); +/// graph._undirectedRelationDefinition("marriage", ["female", "male"]); +/// @END_EXAMPLE_ARANGOSH_OUTPUT +/// //////////////////////////////////////////////////////////////////////////////// @@ -363,7 +422,7 @@ var _edgeDefinitions = function () { var _create = function (graphName, edgeDefinitions) { - var gdb = _getGraphCollection(), + var gdb = getGraphCollection(), g, graphAlreadyExists = true, collections; @@ -463,7 +522,7 @@ var Graph = function(graphName, edgeDefinitions, vertexCollections, edgeCollecti var _graph = function(graphName) { - var gdb = _getGraphCollection(), + var gdb = getGraphCollection(), g, collections; try { @@ -486,7 +545,7 @@ var _graph = function(graphName) { //////////////////////////////////////////////////////////////////////////////// var _exists = function(graphId) { - var gCol = _getGraphCollection(); + var gCol = getGraphCollection(); return gCol.exists(graphId); }; @@ -496,7 +555,7 @@ var _exists = function(graphId) { var _drop = function(graphId, dropCollections) { - var gdb = _getGraphCollection(); + var gdb = getGraphCollection(); if (!gdb.exists(graphId)) { throw "Graph " + graphId + " does not exist."; diff --git a/js/common/tests/shell-general-graph.js b/js/common/tests/shell-general-graph.js index 5a8eda076b..4a92ec0eef 100644 --- a/js/common/tests/shell-general-graph.js +++ b/js/common/tests/shell-general-graph.js @@ -410,6 +410,9 @@ function GeneralGraphCreationSuite() { var vn1 = "UnitTestsVertices"; var vn2 = "UnitTestsVertices2"; var gn = "UnitTestsGraph"; + if(graph._exists(gn)) { + graph._drop(gn); + } var edgeDef = [graph._directedRelationDefinition(en, vn1, vn2)]; var g = graph._create(gn, edgeDef); var v1 = g[vn1].save({_key: "1"})._id; @@ -720,7 +723,6 @@ function GeneralGraphAQLQueriesSuite() { test_filterOnOutEdges: function() { var query = g._outEdges(v1 + "/1").filter({val: true}); - // var query = g._outEdges("v1/1").filter("e.val = true"); assertEqual(query.printQuery(), "FOR edges_0 IN GRAPH_EDGES(" + '@graphName,@startVertex_0,"outbound") ' + 'FILTER MATCHES(edges_0,[{"val":true}])'); @@ -732,7 +734,96 @@ function GeneralGraphAQLQueriesSuite() { assertTrue(findIdInResult(result, e1), "Did not include e1"); assertFalse(findIdInResult(result, e2), "e2 is not excluded"); assertFalse(findIdInResult(result, e3), "e3 is not excluded"); - } + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: counting of query results +//////////////////////////////////////////////////////////////////////////////// + test_queryCount: function() { + var query = g._edges(v1 + "/1"); + assertEqual(query.count(), 3); + query = g._inEdges(v1 + "/1").filter({val: true}); + assertEqual(query.count(), 0); + query = g._outEdges(v1 + "/1").filter({val: true}); + assertEqual(query.count(), 1); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: Cursor iteration +//////////////////////////////////////////////////////////////////////////////// + test_cursorIteration: function() { + var query = g._edges(v1 + "/1"); + var list = [e1, e2, e3]; + var next; + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 2); + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 1); + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 0); + assertFalse(query.hasNext()); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: Cursor recreation after iteration +//////////////////////////////////////////////////////////////////////////////// + test_cursorIterationAndRecreation: function() { + var query = g._edges(v1 + "/1"); + var list = [e1, e2, e3]; + var next; + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 2); + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 1); + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 0); + assertFalse(query.hasNext()); + query = query.filter({val: true}); + list = [e1]; + assertTrue(query.hasNext()); + next = query.next(); + list = _.without(list, next._id); + assertEqual(list.length, 0); + assertFalse(query.hasNext()); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: Is cursor recreated after counting of query results and appending filter +//////////////////////////////////////////////////////////////////////////////// + test_cursorRecreationAfterCount: function() { + var query = g._edges(v1 + "/1"); + assertEqual(query.count(), 3); + query = query.filter({val: true}); + assertEqual(query.count(), 1); + }, + +//////////////////////////////////////////////////////////////////////////////// +/// @brief test: Is cursor recreated after to array of query results and appending filter +//////////////////////////////////////////////////////////////////////////////// + test_cursorRecreationAfterToArray: function() { + var query = g._edges(v1 + "/1"); + var result = query.toArray(); + assertTrue(findIdInResult(result, e1), "Did not include e1"); + assertTrue(findIdInResult(result, e2), "Did not include e2"); + assertTrue(findIdInResult(result, e3), "Did not include e3"); + query = query.filter({val: true}); + result = query.toArray(); + assertTrue(findIdInResult(result, e1), "Did not include e1"); + assertFalse(findIdInResult(result, e2), "e2 is not excluded"); + assertFalse(findIdInResult(result, e3), "e3 is not excluded"); + } //////////////////////////////////////////////////////////////////////////////// /// @brief test: let construct on edges @@ -840,12 +931,6 @@ function EdgesAndVerticesSuite() { }, tearDown : function() { - db.unitTestVertexCollection1.drop(); - db.unitTestVertexCollection2.drop(); - db.unitTestVertexCollection3.drop(); - db.unitTestVertexCollection4.drop(); - db.unitTestEdgeCollection1.drop(); - db.unitTestEdgeCollection2.drop(); graph._drop("unitTestGraph"); },