1
0
Fork 0

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

This commit is contained in:
a-brandt 2013-01-10 14:48:26 +01:00
commit c1fec4c5b0
103 changed files with 4994 additions and 2722 deletions

View File

@ -1,6 +1,8 @@
v1.2.alpha (XXXX-XX-XX)
-----------------------
* added collection.revision() method to determine whether a collection has changed
* issue #346: adaptively determine NUMBER_HEADERS_PER_BLOCK
* issue #338: arangosh cursor positioning problems

View File

@ -1,2 +0,0 @@
arango> db.example.document("1432124/2873916");
{ "_id" : "1432124/2873916", "_rev" : 2873916, "Hallo" : "World" }

View File

@ -1,5 +0,0 @@
arango> db.example.document("12345");
JavaScript exception in file '(arango)' at 1,12:
[ArangoError 10: bad parameter: <document-identifier> must be a document identifier]
!db.example.document("12345");
! ^

View File

@ -1,5 +0,0 @@
arango> db.example.document("1432124/123456");
JavaScript exception in file '(arango)' at 1,12:
[ArangoError 1202: document not found: document not found]
!db.example.document("1432124/123456");
! ^

View File

@ -1,9 +0,0 @@
arango> col = db.examples;
[ArangoCollection 91022, "examples" (status new born)]
arango> col.save({ "Hallo" : "World" });
{ "_id" : "91022/1532814", "_rev" : 1532814 }
arango> col.count();
1
arango> col.truncate();
arango> col.count();
0

View File

@ -1,4 +0,0 @@
arango> db.example.getIndexes().map(function(x) { return x.id; });
["93013/0"]
arango> db.example.index("93013/0");
{ "id" : "93013/0", "type" : "primary", "fields" : ["_id"] }

View File

@ -1,10 +0,0 @@
arango> a1 = db.example.save({ a : 1 });
{ "_id" : "116308/3449537", "_rev" : 3449537 }
arango> db.example.document(a1);
{ "_id" : "116308/3449537", "_rev" : 3449537, "a" : 1 }
arango> db.example.delete(a1);
true
arango> db.example.document(a1);
JavaScript exception in file '(arango)' at 1,12: [ArangoError 1202: document not found: document not found]
!db.example.document(a1);
! ^

View File

@ -1,14 +0,0 @@
arango> a1 = db.example.save({ a : 1 });
{ "_id" : "116308/3857139", "_rev" : 3857139 }
arango> a2 = db.example.replace(a1, { a : 2 });
{ "_id" : "116308/3857139", "_rev" : 3922675, "_oldRev" : 3857139 }
arango> db.example.delete(a1);
JavaScript exception in file '(arango)' at 1,18: [ArangoError 1200: conflict: cannot delete document]
!db.example.delete(a1);
! ^
arango> db.example.delete(a1, true);
true
arango> db.example.document(a1);
JavaScript exception in file '(arango)' at 1,12: [ArangoError 1202: document not found: document not found]
!db.example.document(a1);
! ^

View File

@ -1,14 +0,0 @@
arango> a1 = db.example.save({ a : 1 });
{ "_id" : "116308/4042634", "_rev" : 4042634 }
arango> a2 = db._replace(a1, { a : 2 });
{ "_id" : "116308/4042634", "_rev" : 4108170, "_oldRev" : 4042634 }
arango> db._delete(a1);
JavaScript exception in file '(arango)' at 1,4: [ArangoError 1200: conflict: cannot delete document]
!db._delete(a1);
! ^
arango> db._delete(a1, true);
true
arango> db._document(a1);
JavaScript exception in file '(arango)' at 1,4: [ArangoError 1202: document not found: document not found]
!db._document(a1);
! ^

View File

@ -1,10 +0,0 @@
arango> a1 = db.example.save({ a : 1 });
{ "_id" : "116308/4214943", "_rev" : 4214943 }
arango> db._delete(a1);
true
arango> db._delete(a1);
JavaScript exception in file '(arango)' at 1,4: [ArangoError 1202: document not found: cannot delete document]
!db._delete(a1);
! ^
arango> db._delete(a1, true);
false

View File

@ -28,7 +28,8 @@ DOXYGEN = \
Doxygen/js/actions/system/api-simple.c \
Doxygen/js/actions/system/api-system.c \
Doxygen/js/common/bootstrap/modules.c \
Doxygen/js/common/bootstrap/print.c \
Doxygen/js/common/bootstrap/module-console.c \
Doxygen/js/common/bootstrap/module-fs.c \
Doxygen/js/common/modules/graph.c \
Doxygen/js/common/modules/jsunity.c \
Doxygen/js/common/modules/simple-query-basics.c \
@ -36,6 +37,7 @@ DOXYGEN = \
Doxygen/js/common/modules/users.c \
Doxygen/js/server/modules/org/arangodb/actions.c \
Doxygen/js/server/modules/simple-query.c \
Doxygen/js/server/ArangoCollection.c \
Doxygen/js/server/server.c
################################################################################

View File

@ -0,0 +1,22 @@
Module "fs" {#JSModuleFs}
=========================
@EMBEDTOC{JSModuleFsTOC}
The implementation follows the CommonJS specification
@EXTREF{http://wiki.commonjs.org/wiki/Filesystem/A/0,Filesystem/A/0}.
@anchor JSModuleFsExists
@copydetails JS_Exists
@anchor JSModuleFsIsDirectory
@copydetails JS_IsDirectory
@anchor JSModuleFsListTree
@copydetails JS_ListTree
@anchor JSModuleFsMove
@copydetails JS_Move
@anchor JSModuleFsRemove
@copydetails JS_Remove

View File

@ -0,0 +1,9 @@
TOC {#JSModuleFsTOC}
====================
- @ref JSModuleFs
- @ref JSModuleFsExists "fs.exists"
- @ref JSModuleFsIsDirectory "fs.isDirectory"
- @ref JSModuleFsListTree "fs.listTree"
- @ref JSModuleFsMove "fs.move"
- @ref JSModuleFsRemove "fs.remove"

View File

@ -305,7 +305,7 @@ A Simple Action {#UserManualActionsContentAction}
The simplest dynamic action is:
{ action: { controller: "org/arangodb/actions", do: "echoRequest" } }
{ action: { do: "org/arangodb/actions/echoRequest" } }
It is not possible to store functions directly in the routing table, but you can
call functions defined in modules. In the above example the function can be
@ -324,7 +324,7 @@ For example
arangosh> db._routing.save({
........> url: "/hello/echo",
........> action: { controller: "org/arangodb/actions", do: "echoRequest" } });
........> action: { do: "org/arangodb/actions/echoRequest" } });
Reload the routing and check
@ -645,3 +645,99 @@ should win in this case:
........> ]
........> });
Application Deployment {#UserManualActionsApplicationDeployment}
================================================================
Using single routes or @ref UserManualActionsAdvancedBundles "bundles" can be
become a bit messy in large applications. Therefore a deployment tool exists
inside _arangosh_ to simplify the task. This tool was inspired by the ArangoDB
deployment tool `https://github.com/kaerus/arangodep` written in node.js by
kaerus.
An application is a bunch of routes, static pages stored in collections, and
small scriptlets stored modules.
In order to create an application, chose a suitable name, e. g. reverse domain
name plus the application name and call `createApp`:
arangosh> var deploy = require("org/arangodb/deploy");
arangosh> var app = deploy.createApp("org.example.simple");
Normally content will either be stored in collections or dynamically
calculated. But sometimes it is convenient to store the content directly in the
routing table, e. g. to deliver a version number.
arangosh> app.mountStaticContent("/version", {
........> version: "1.2.3", major: 1, minor: 2, patch: 3 });
[ArangoApp "org.example.simple" at ""]
Save the application
arangosh> app.save();
[ArangoApp "org.example.simple" at ""]
and use the browser to check the result
http://localhost:8529/version
You can also specify the content-type
arangosh> app.mountStaticContent("/author",
........> "Frank Celler",
........> "text/plain").save();
[ArangoApp "org.example.simple" at ""]
and check at
http://localhost:8529/author
If you have more than one application, putting version under `/` might lead to
conflicts. It is therefore possible to use a common prefix for the application.
arangosh> app.setPrefix("/example").save();
[ArangoApp "org.example.simple" at "/example"]
Now check
http://localhost:8529/example/version
http://localhost:8529/example/author
Deploying Static Pages {#UserManualActionsDeployingStaticPages}
---------------------------------------------------------------
Most of the time, static html pages and JavaScript content will be delivered by
your web-server. But sometimes it is convenient to deliver these directly from
within ArangoDB. For example, to provide a small admin interface for you
application.
Assume that all data is stored underneath a directory "/tmp/example" and we want
to store the content in a collection "org_example_simple_content".
First connect the url path to the collection.
arangosh> app.mountStaticPages("/static", "org_example_simple_content").save();
[ArangoApp "org.example.simple" at "/example"]
Next create a file `index.html` at `/tmp/example/index.html".
<html>
<body>
Hallo World!
</body>
</html>
Create the collection and upload this into the collection
arangosh> require("org/arangodb").db._createDocumentCollection("org_example_simple_content");
[ArangoCollection 224910918055, "org_example_simple_content" (type document, status loaded)]
arangosh> app.uploadStaticPages("/static", "/tmp/example");
imported '/index.html' of type 'text/html; charset=utf-8'
[ArangoApp "org.example.simple" at "/example"]
Check the index file
http://localhost:8529/example/static/index.html

View File

@ -25,3 +25,5 @@ TOC {#UserManualActionsTOC}
- @ref UserManualActionsAdvancedRedirects
- @ref UserManualActionsAdvancedBundles
- @ref UserManualActionsAdvancedMiddleware
- @ref UserManualActionsApplicationDeployment
- @ref UserManualActionsDeployingStaticPages

View File

@ -0,0 +1,120 @@
Handling Documents {#ShellDocument}
===================================
@NAVIGATE_ShellDocument
@EMBEDTOC{ShellDocumentTOC}
This is an introduction to ArangoDB's interface for documents and how handle
documents from the JavaScript shell _arangosh_. For other languages see
the corresponding language API.
Documents, Identifiers, Handles {#ShellDocumentIntro}
=====================================================
@copydoc GlossaryDocument
For example:
{
"_id" : "demo/2345678",
"_rev" : "3456789",
"_key" : "2345678",
"firstName" : "Hugo",
"lastName" : "Schlonz",
"address" : {
"street" : "Strasse 1",
"city" : "Hier"
},
"hobbies" : [
"swimming",
"biking",
"programming"
]
}
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
`_rev`. The value of the `_key` attribute can be specified by the user when
creating a document. `_id` and `_key` values are immutable once the document
has been created. The `_rev` value is maintained by ArangoDB autonomously.
@copydoc GlossaryDocumentHandle
@copydoc GlossaryDocumentIdentifier
@copydoc GlossaryDocumentRevision
@copydoc GlossaryDocumentEtag
Address and ETag of an Document {#ShellDocumentResource}
========================================================
All documents in ArangoDB have a document handle. This handle uniquely defines a
document and is managed by ArangoDB. The interface allows you to access the
documents of a collection as:
db.@FA{collection}.documet(@FA{document-handle})
For example: Assume that the document handle, which is stored in the `_id` field
of the document, is `demo/362549` and the document lives in a collection
named @FA{demo}, then that document can be accessed as:
db.demo.document("demo/362549736")
Because the document handle is unique within the database, you
can leave out the @FA{collection} and use the shortcut:
db._document("demo/362549736")
Each document also has a document revision or etag with is returned in the
`_rev` field when requesting a document. The document's key is returned in the
`_key` attribute.
@CLEARPAGE
Working with Documents {#ShellDocumentShell}
============================================
Collection Methods {#ShellDocumentCollectionMethods}
----------------------------------------------------
@anchor ShellDocumentRead
@copydetails JS_DocumentVocbaseCol
@CLEARPAGE
@anchor ShellDocumentCreate
@copydetails JS_SaveVocbaseCol
@CLEARPAGE
@anchor ShellDocumentReplace
@copydetails JS_ReplaceVocbaseCol
@CLEARPAGE
@anchor ShellDocumentUpdate
@copydetails JS_UpdateVocbaseCol
@CLEARPAGE
@anchor ShellDocumentRemove
@copydetails JS_RemoveVocbaseCol
@CLEARPAGE
@anchor ShellDocumentRemoveByExample
@copydetails JSF_ArangoCollection_prototype_removeByExample
@CLEARPAGE
Database Methods {#ShellDocumentDatabaseMethods}
------------------------------------------------
@anchor ShellDocumentDbRead
@copydetails JS_DocumentVocbase
@CLEARPAGE
@anchor ShellDocumentDbReplace
@copydetails JS_ReplaceVocbase
@CLEARPAGE
@anchor ShellDocumentDbUpdate
@copydetails JS_UpdateVocbase
@CLEARPAGE
@anchor ShellDocumentDbRemove
@copydetails JS_RemoveVocbase

View File

@ -0,0 +1,19 @@
TOC {#ShellDocumentTOC}
=======================
- @ref ShellDocument
- @ref ShellDocumentIntro
- @ref ShellDocumentResource
- @ref ShellDocumentShell
- @ref ShellDocumentCollectionMethods
- @ref ShellDocumentRead "collection.document"
- @ref ShellDocumentCreate "collection.save"
- @ref ShellDocumentReplace "collection.replace"
- @ref ShellDocumentUpdate "collection.update"
- @ref ShellDocumentRemove "collection.remove"
- @ref ShellDocumentRemoveByExample "collection.removeByExample"
- @ref ShellDocumentDatabaseMethods
- @ref ShellDocumentDbRead "db._document"
- @ref ShellDocumentDbReplace "db._replace"
- @ref ShellDocumentDbUpdate "db._update"
- @ref ShellDocumentDbRemove "db._remove"

View File

@ -197,26 +197,26 @@ TAB_SIZE = 8
# function definition
ALIASES = \
"FUN{1}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FUN{2}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1, \2@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FUN{3}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1, \2, \3@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FUN{4}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1, \2, \3, \4@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FUN{5}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1, \2, \3, \4, \5@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FUN{6}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1, \2, \3, \4, \5, \6@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FUN{7}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1, \2, \3, \4, \5, \6, \7@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FA{1}=@latexonly\functionargument{@endlatexonly@htmlonly<span class=\"functionargument\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"FN{1}=@latexonly\functionname{@endlatexonly@htmlonly<span class=\"functionname\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly XMLMISSING @endxmlonly"
"FUN{1}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FUN{2}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1, \2@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FUN{3}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1, \2, \3@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FUN{4}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1, \2, \3, \4@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FUN{5}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1, \2, \3, \4, \5@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FUN{6}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1, \2, \3, \4, \5, \6@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FUN{7}=@latexonly\functionsignature{@endlatexonly@htmlonly<div class=\"functionsignature\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1, \2, \3, \4, \5, \6, \7@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FA{1}=@latexonly\functionargument{@endlatexonly@htmlonly<span class=\"functionargument\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"FN{1}=@latexonly\functionname{@endlatexonly@htmlonly<span class=\"functionname\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly"
# command line option
ALIASES += \
"CMDOPT{1}=@latexonly\commandlineoption{@endlatexonly@htmlonly<div class=\"commandlineoption\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"CA{1}=@latexonly\commandlineargument{@endlatexonly@htmlonly<span class=\"commandlineargument\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"CO{1}=@latexonly\commandoption{@endlatexon\@htmlonly<span class=\"commandoption\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly XMLMISSING @endxmlonly"
"CMDOPT{1}=@latexonly\commandlineoption{@endlatexonly@htmlonly<div class=\"commandlineoption\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"CA{1}=@latexonly\commandlineargument{@endlatexonly@htmlonly<span class=\"commandlineargument\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"CO{1}=@latexonly\commandoption{@endlatexonly@htmlonly<span class=\"commandoption\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly"
# rest calls
ALIASES += \
"RESTHEADER{2}=@latexonly\restheader{@endlatexonly@htmlonly<div class=\"restheader\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly,@endlatexonly@htmlonly<div class=\"restheaderremark\">(@endhtmlonly@xmlonly XMLMISSING @endxmlonly\2@latexonly}@endlatexonly@htmlonly)</div></div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly" \
"REST{1}=@latexonly\restcall{@endlatexonly@htmlonly<div class=\"restcall\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly XMLMISSING @endxmlonly"
"RESTHEADER{2}=@latexonly\restheader{@endlatexonly@htmlonly<div class=\"restheader\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly,@endlatexonly@htmlonly<div class=\"restheaderremark\">(@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\2@latexonly}@endlatexonly@htmlonly)</div></div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly" \
"REST{1}=@latexonly\restcall{@endlatexonly@htmlonly<div class=\"restcall\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</div>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly"
# navigation
ALIASES += \
@ -227,7 +227,7 @@ ALIASES += \
# glossary
ALIASES += \
"GE{1}=@latexonly\glossaryentry{@endlatexonly@htmlonly<span class=\"glossaryentry\">@endhtmlonly@xmlonly XMLMISSING @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly XMLMISSING @endxmlonly"
"GE{1}=@latexonly\glossaryentry{@endlatexonly@htmlonly<span class=\"glossaryentry\">@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly\1@latexonly}@endlatexonly@htmlonly</span>@endhtmlonly@xmlonly <!--- XMLMISSING --> @endxmlonly"
# examples
ALIASES += \
@ -723,7 +723,8 @@ WARN_LOGFILE =
INPUT = @srcdir@/Documentation/DbaManual \
@srcdir@/Documentation/InstallationManual \
@srcdir@/Documentation/Manual \
@srcdir@/Documentation/UserManual \
@srcdir@/Documentation/RefManual \
@srcdir@/Documentation/UserManual \
@srcdir@/Doxygen/js \
@srcdir@/arangod \
@srcdir@/lib

View File

@ -324,8 +324,7 @@ clean-local:
built-sources: \
build_posix.h \
@top_srcdir@/js/common/bootstrap/errors.js \
$(JAVASCRIPT_HEADER)
@top_srcdir@/js/common/bootstrap/errors.js
################################################################################
### @brief tags file

View File

@ -4,22 +4,6 @@
## --SECTION-- JAVASCRIPT
## -----------------------------------------------------------------------------
################################################################################
### @brief JavaScript source code as header
################################################################################
JAVASCRIPT_HEADER = \
js/common/bootstrap/js-errors.h \
js/common/bootstrap/js-modules.h \
js/common/bootstrap/js-monkeypatches.h \
js/common/bootstrap/js-print.h \
js/client/js-client.h \
js/server/js-server.h \
js/server/js-version-check.h \
js/server/js-ahuacatl.h
BUILT_SOURCES += $(JAVASCRIPT_HEADER)
################################################################################
### @brief JavaScript modules for browser
################################################################################

View File

@ -58,7 +58,7 @@ describe ArangoDB do
# create collection with one document
@cid = ArangoDB.create_collection(cn)
cmd = "/_api/document?collection=#{@cid}"
cmd = "/_api/document?collection=#{cn}"
body = "{ \"Hello\" : \"World\" }"
doc = ArangoDB.log_post("#{prefix}", cmd, :body => body)

View File

@ -374,6 +374,7 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
len = strlen(lookFor);
}
else {
// "any" will not be optimised
lookFor = NULL;
len = 0;
}
@ -395,6 +396,110 @@ static void OptimisePaths (const TRI_aql_node_t* const fcallNode,
hint = (TRI_aql_collection_hint_t*) (TRI_AQL_NODE_DATA(vertexCollection));
hint->_ranges = TRI_AddAccessAql(context, hint->_ranges, fieldAccess);
}
if (args->_members._length <= 4 &&
TRI_EqualString(name, ".edges.LENGTH()")) {
// length restriction, can only be applied if length parameters are not already set
TRI_aql_node_t* argNode;
TRI_json_t* value;
double minValue = 0.0;
double maxValue = 0.0;
bool useMin = false;
bool useMax = false;
if (fieldAccess->_type == TRI_AQL_ACCESS_EXACT) {
value = fieldAccess->_value._value;
if (value != NULL && value->_type == TRI_JSON_NUMBER) {
// LENGTH(p.edges) == const
minValue = maxValue = value->_value._number;
useMin = useMax = true;
}
}
else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_SINGLE) {
value = fieldAccess->_value._singleRange._value;
if (value != NULL && value->_type == TRI_JSON_NUMBER) {
// LENGTH(p.edges) operator const
if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_LOWER_INCLUDED) {
minValue = value->_value._number;
useMin = true;
}
else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_UPPER_INCLUDED) {
maxValue = value->_value._number;
useMax = true;
}
else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_LOWER_EXCLUDED) {
if ((double) ((int) value->_value._number) == value->_value._number) {
minValue = value->_value._number + 1.0;
useMin = true;
}
}
else if (fieldAccess->_value._singleRange._type == TRI_AQL_RANGE_UPPER_EXCLUDED) {
if ((double) ((int) value->_value._number) == value->_value._number) {
maxValue = value->_value._number - 1.0;
useMax = true;
}
}
}
}
else if (fieldAccess->_type == TRI_AQL_ACCESS_RANGE_DOUBLE) {
// LENGTH(p.edges) > const && LENGTH(p.edges) < const
value = fieldAccess->_value._between._lower._value;
if (value != NULL && value->_type == TRI_JSON_NUMBER) {
if (fieldAccess->_value._between._lower._type == TRI_AQL_RANGE_LOWER_INCLUDED) {
minValue = value->_value._number;
useMin = true;
}
else if (fieldAccess->_value._between._lower._type == TRI_AQL_RANGE_LOWER_EXCLUDED) {
if ((double) ((int) value->_value._number) == value->_value._number) {
minValue = value->_value._number + 1.0;
useMin = true;
}
}
}
value = fieldAccess->_value._between._upper._value;
if (value != NULL && value->_type == TRI_JSON_NUMBER) {
if (fieldAccess->_value._between._upper._type == TRI_AQL_RANGE_UPPER_INCLUDED) {
maxValue = value->_value._number;
useMax = true;
}
else if (fieldAccess->_value._between._upper._type == TRI_AQL_RANGE_UPPER_EXCLUDED) {
if ((double) ((int) value->_value._number) == value->_value._number) {
maxValue = value->_value._number - 1.0;
useMax = true;
}
}
}
}
if (useMin || useMax) {
// minLength and maxLength are parameters 5 & 6
// add as many null value nodes as are missing
while (args->_members._length < 4) {
argNode = TRI_CreateNodeValueNullAql(context);
if (argNode) {
TRI_PushBackVectorPointer(&args->_members, (void*) argNode);
}
}
// add min and max values to the function call argument list
argNode = TRI_CreateNodeValueIntAql(context, useMin ? (int64_t) minValue : (int64_t) 0);
if (argNode) {
// min value node
TRI_PushBackVectorPointer(&args->_members, (void*) argNode);
argNode = TRI_CreateNodeValueIntAql(context, useMax ? (int64_t) maxValue : (int64_t) (1024 * 1024));
if (argNode) {
// max value node
TRI_PushBackVectorPointer(&args->_members, (void*) argNode);
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -119,37 +119,37 @@
///////////////////////////////////////////////////////////////////////////
///
/// @anchor HttpCollectionCreate
/// @copydetails JSF_POST_api_collection
/// @copydetails JSF_post_api_collection
///
/// @anchor HttpCollectionDelete
/// @copydetails JSF_DELETE_api_collection
/// @copydetails JSF_delete_api_collection
///
/// @anchor HttpCollectionTruncate
/// @copydetails JSF_PUT_api_collection_truncate
/// @copydetails JSF_put_api_collection_truncate
///
/// @subsection HttpCollectionReading Getting Information about a Collection
////////////////////////////////////////////////////////////////////////////
///
/// @anchor HttpCollectionRead
/// @copydetails JSF_GET_api_collection
/// @copydetails JSF_get_api_collection
///
/// @anchor HttpCollectionReadAll
/// @copydetails JSF_GET_api_collections
/// @copydetails JSF_get_api_collections
///
/// @subsection HttpCollectionChanging Modifying a Collection
/////////////////////////////////////////////////////////////
///
/// @anchor HttpCollectionLoad
/// @copydetails JSF_PUT_api_collection_load
/// @copydetails JSF_put_api_collection_load
///
/// @anchor HttpCollectionUnload
/// @copydetails JSF_PUT_api_collection_unload
/// @copydetails JSF_put_api_collection_unload
///
/// @anchor HttpCollectionProperties
/// @copydetails JSF_PUT_api_collection_properties
/// @copydetails JSF_put_api_collection_properties
///
/// @anchor HttpCollectionRename
/// @copydetails JSF_PUT_api_collection_rename
/// @copydetails JSF_put_api_collection_rename
////////////////////////////////////////////////////////////////////////////////
// Local Variables:

View File

@ -1,53 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief module "fs"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 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
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page JSModuleFsTOC
///
/// <ol>
/// <li>@ref JSModuleFsExists "fs.exists"</li>
/// </ol>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page JSModuleFs Module "fs"
///
/// The implementation follows the CommonJS specification
/// <a href="http://wiki.commonjs.org/wiki/Filesystem/A/0">Filesystem/A/0</a>.
///
/// <hr>
/// @copydoc JSModuleFsTOC
/// <hr>
///
/// @anchor JSModuleFsExists
/// @copydetails JS_Exists
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:

View File

@ -1,186 +0,0 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief arango shell
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 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
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- HANDLING DOCUMENTS
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @page ShellDocumentTOC
///
/// <ul>
/// <li>@ref ShellDocument
/// <ul>
/// <li>@ref ShellDocumentIntro</li>
/// <li>@ref ShellDocumentResource</li>
/// <li>@ref ShellDocumentShell
/// @copydetails ShellDocumentCallsTOC
/// </li>
/// </ul>
/// </li>
/// </ul>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page ShellDocumentCallsTOC
///
/// <ul>
/// <li>@ref ShellDocumentCollectionMethods
/// <ul>
/// <li>@ref ShellDocumentRead "collection.document"</li>
/// <li>@ref ShellDocumentCreate "collection.save"</li>
/// <li>@ref ShellDocumentReplace "collection.replace"</li>
/// <li>@ref ShellDocumentUpdate "collection.update"</li>
/// <li>@ref ShellDocumentDelete "collection.remove"</li>
/// </ul>
/// </li>
/// <li>@ref ShellDocumentDatabaseMethods
/// <ul>
/// <li>@ref ShellDocumentDbRead "db._document"</li>
/// <li>@ref ShellDocumentDbReplace "db._replace"</li>
/// <li>@ref ShellDocumentDbUpdate "db._update"</li>
/// <li>@ref ShellDocumentDbDelete "db._remove"</li>
/// </ul>
/// </li>
/// </ul>
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @page ShellDocument Handling Documents
///
/// @NAVIGATE_ShellDocument
///
/// This is an introduction to ArangoDB's interface for documents and how handle
/// documents from the JavaScript shell @LIT{arangosh}. For other languages see
/// the corresponding language API.
///
/// @EMBEDTOC{ShellDocumentTOC}
///
/// @section ShellDocumentIntro Documents, Identifiers, Handles
///////////////////////////////////////////////////////////////
///
/// @copydoc GlossaryDocument
///
/// For example:
///
/// @verbinclude document1
///
/// All documents contain special attributes: the document handle in @LIT{_id},
/// the document's unique key in @LIT{_key} and and the etag aka document
/// revision in @LIT{_rev}. The value of the @LIT{_key} attribute can be
/// specified by the user when creating a document.
/// @LIT{_id} and @LIT{_key} values are immutable once the document has been
/// created. The @LIT{_rev} value is maintained by ArangoDB autonomously.
///
/// @copydoc GlossaryDocumentHandle
///
/// @copydoc GlossaryDocumentKey
///
/// @copydoc GlossaryDocumentRevision
///
/// @copydoc GlossaryDocumentEtag
///
/// @section ShellDocumentResource Address and ETag of an Document
//////////////////////////////////////////////////////////////////
///
/// All documents in ArangoDB have a document handle. This handle uniquely
/// defines a document and is managed by ArangoDB. The interface allows
/// you to access the documents of a collection as:
///
/// @LIT{db.@FA{collection}.documet(@FA{document-handle})}
///
/// For example: Assume that the document handle, which is stored in
/// the @LIT{_id} attribute of the document, is @LIT{demo/362549736}
/// and the document lives in a collection named @FA{demo}, then
/// that document can be accessed as:
///
/// @LIT{db.demo.document("demo/362549736")}
///
/// Because the document handle is unique within the database, you
/// can leave out the @FA{collection} and use the shortcut:
///
/// @LIT{db._document("demo/362549736")}
///
/// Each document also has a document revision or etag with is returned
/// in the @LIT{_rev} attribute when requesting a document. The document's
/// key is returned in the @LIT{_key} attribute.
///
/// @CLEARPAGE
/// @section ShellDocumentShell Working with Documents
//////////////////////////////////////////////////////
///
/// @subsection ShellDocumentCollectionMethods Collection Methods
/////////////////////////////////////////////////////////////////
///
/// @anchor ShellDocumentRead
/// @copydetails JS_DocumentVocbaseCol
///
/// @CLEARPAGE
/// @anchor ShellDocumentCreate
/// @copydetails JS_SaveVocbaseCol
///
/// @CLEARPAGE
/// @anchor ShellDocumentReplace
/// @copydetails JS_ReplaceVocbaseCol
///
/// @CLEARPAGE
/// @anchor ShellDocumentUpdate
/// @copydetails JS_UpdateVocbaseCol
///
/// @CLEARPAGE
/// @anchor ShellDocumentDelete
/// @copydetails JS_RemoveVocbaseCol
///
/// @CLEARPAGE
/// @subsection ShellDocumentDatabaseMethods Database Methods
/////////////////////////////////////////////////////////////
///
/// @anchor ShellDocumentDbRead
/// @copydetails JS_DocumentVocbase
///
/// @CLEARPAGE
/// @anchor ShellDocumentDbReplace
/// @copydetails JS_ReplaceVocbase
///
/// @CLEARPAGE
/// @anchor ShellDocumentDbUpdate
/// @copydetails JS_UpdateVocbase
///
/// @CLEARPAGE
/// @anchor ShellDocumentDbDelete
/// @copydetails JS_RemoveVocbase
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: c++
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:

View File

@ -1,5 +1,5 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief installation guide
/// @brief simple queries
///
/// @file
///

View File

@ -280,7 +280,7 @@ bool RestDocumentHandler::createDocument () {
}
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection, getCollectionType(), create);
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection, create, getCollectionType());
// .............................................................................
// inside write transaction
@ -402,7 +402,7 @@ bool RestDocumentHandler::readSingleDocument (bool generateBody) {
string key = suffix[1];
// find and load collection given by name or identifier
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, getCollectionType());
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
// .............................................................................
// inside read transaction
@ -486,7 +486,7 @@ bool RestDocumentHandler::readAllDocuments () {
string collection = _request->value("collection", found);
// find and load collection given by name or identifier
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, getCollectionType());
SingleCollectionReadOnlyTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection);
vector<string> ids;
@ -757,7 +757,7 @@ bool RestDocumentHandler::modifyDocument (bool isPatch) {
TRI_doc_update_policy_e policy = extractUpdatePolicy();
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection, getCollectionType(), false);
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection);
TRI_doc_mptr_t* document = 0;
TRI_voc_rid_t rid = 0;
@ -918,7 +918,7 @@ bool RestDocumentHandler::deleteDocument () {
}
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection, getCollectionType(), false);
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection);
TRI_voc_rid_t rid = 0;
// .............................................................................

View File

@ -163,7 +163,7 @@ bool RestEdgeHandler::createDocument () {
}
// find and load collection given by name or identifier
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection, getCollectionType(), create);
SelfContainedWriteTransaction<RestTransactionContext> trx(_vocbase, collection, create, getCollectionType());
// .............................................................................
// inside write transaction

View File

@ -205,7 +205,7 @@ bool RestImportHandler::createByDocumentsLines () {
bool create = found ? StringUtils::boolean(valueStr) : false;
// find and load collection given by name or identifier
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, TRI_COL_TYPE_DOCUMENT, create);
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, create, TRI_COL_TYPE_DOCUMENT);
// .............................................................................
// inside write transaction
@ -350,7 +350,7 @@ bool RestImportHandler::createByDocumentsList () {
bool create = found ? StringUtils::boolean(valueStr) : false;
// find and load collection given by name or identifier
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, TRI_COL_TYPE_DOCUMENT, create);
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, create, TRI_COL_TYPE_DOCUMENT);
// .............................................................................
// inside write transaction
@ -498,7 +498,7 @@ bool RestImportHandler::createByKeyValueList () {
}
// find and load collection given by name or identifier
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, TRI_COL_TYPE_DOCUMENT, create);
ImportTransaction<StandaloneTransaction<RestTransactionContext> > trx(_vocbase, collection, create, TRI_COL_TYPE_DOCUMENT);
// .............................................................................
// inside write transaction

View File

@ -953,7 +953,7 @@ mrb_value MR_ArangoDatabase_Collection (mrb_state* mrb, mrb_value self) {
// looking at "mruby.h" I assume that is the way to unwrap the pointer
rdata = (struct RData*) mrb_object(self);
vocbase = (TRI_vocbase_t*) rdata->data;
collection = TRI_FindCollectionByNameVocBase(vocbase, name, false);
collection = TRI_LookupCollectionByNameVocBase(vocbase, name);
if (collection == NULL) {
printf("unknown collection (TODO raise error)\n");

View File

@ -64,7 +64,7 @@ namespace triagens {
if (_trx != 0) {
if (_trx->_status == TRI_TRANSACTION_RUNNING) {
// auto abort
abort();
this->abort();
}
TRI_FreeTransaction(_trx);

View File

@ -62,10 +62,10 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
ImportTransaction (TRI_vocbase_t* const vocbase,
const string& collectionName,
const TRI_col_type_e collectionType,
const bool createCollection) :
SingleCollectionWriteTransaction<T, UINT64_MAX>(vocbase, collectionName, collectionType, createCollection, "ImportTransaction") {
const string& name,
const bool create,
const TRI_col_type_e createType) :
SingleCollectionWriteTransaction<T, UINT64_MAX>(vocbase, name, create, createType) {
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -64,10 +64,35 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
SelfContainedWriteTransaction (TRI_vocbase_t* const vocbase,
const string& collectionName,
const TRI_col_type_e collectionType,
const bool createCollection) :
SingleCollectionWriteTransaction<StandaloneTransaction<C>, 1>(vocbase, collectionName, collectionType, createCollection, "SelfContainedWriteTransaction") {
const string& name) :
SingleCollectionWriteTransaction<StandaloneTransaction<C>, 1>(vocbase, name) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create the transaction, using a collection object
///
/// A self contained write transaction operates on a single collection and may
/// execute at most one write operation
////////////////////////////////////////////////////////////////////////////////
SelfContainedWriteTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const TRI_col_type_e createType) :
SingleCollectionWriteTransaction<StandaloneTransaction<C>, 1>(vocbase, name, createType) {
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create the transaction, using a collection object
///
/// A self contained write transaction operates on a single collection and may
/// execute at most one write operation
////////////////////////////////////////////////////////////////////////////////
SelfContainedWriteTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const bool create,
const TRI_col_type_e createType) :
SingleCollectionWriteTransaction<StandaloneTransaction<C>, 1>(vocbase, name, create, createType) {
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -62,9 +62,8 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
SingleCollectionReadOnlyTransaction (TRI_vocbase_t* const vocbase,
const string& collectionName,
const TRI_col_type_e collectionType) :
SingleCollectionTransaction<T>(vocbase, collectionName, collectionType, false, "SingleCollectionReadOnlyTransaction", TRI_TRANSACTION_READ) {
const string& name) :
SingleCollectionTransaction<T>(vocbase, name, TRI_TRANSACTION_READ) {
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -71,16 +71,29 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
SingleCollectionTransaction (TRI_vocbase_t* const vocbase,
const string& collectionName,
const TRI_col_type_e collectionType,
const bool createCollection,
const string& trxName,
const TRI_transaction_type_e type) :
Transaction<T>(vocbase, trxName),
_collectionName(collectionName),
_collectionType(collectionType),
_createCollection(createCollection),
_type(type),
const string& name,
const TRI_transaction_type_e accessType) :
Transaction<T>(vocbase, new TransactionCollectionsList(vocbase, name, accessType)),
_name(name),
_collection(0) {
}
SingleCollectionTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const TRI_transaction_type_e accessType,
const TRI_col_type_e createType) :
Transaction<T>(vocbase, new TransactionCollectionsList(vocbase, name, accessType, createType)),
_name(name),
_collection(0) {
}
SingleCollectionTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const TRI_transaction_type_e accessType,
const bool create,
const TRI_col_type_e createType) :
Transaction<T>(vocbase, new TransactionCollectionsList(vocbase, name, accessType, create, createType)),
_name(name),
_collection(0) {
}
@ -89,103 +102,6 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
virtual ~SingleCollectionTransaction () {
if (! this->isEmbedded()) {
if (this->_trx != 0) {
if (this->status() == TRI_TRANSACTION_RUNNING) {
// auto abort
this->abort();
}
}
releaseCollection();
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- virtual protected functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
protected:
////////////////////////////////////////////////////////////////////////////////
/// @brief use the underlying collection
////////////////////////////////////////////////////////////////////////////////
int useCollections () {
if (_collection != 0) {
// we already used this collectino, nothing to do
return TRI_ERROR_NO_ERROR;
}
if (_collectionName.empty()) {
// name is empty. cannot open the collection
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
}
// open or create the collection
if (isdigit(_collectionName[0])) {
TRI_voc_cid_t id = triagens::basics::StringUtils::uint64(_collectionName);
_collection = TRI_LookupCollectionByIdVocBase(this->_vocbase, id);
}
else {
if (_collectionType == TRI_COL_TYPE_DOCUMENT) {
_collection = TRI_FindDocumentCollectionByNameVocBase(this->_vocbase, _collectionName.c_str(), _createCollection);
}
else if (_collectionType == TRI_COL_TYPE_EDGE) {
_collection = TRI_FindEdgeCollectionByNameVocBase(this->_vocbase, _collectionName.c_str(), _createCollection);
}
}
if (_collection == 0) {
// collection not found
return TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
}
int res = TRI_UseCollectionVocBase(this->_vocbase, const_cast<TRI_vocbase_col_s*>(_collection));
if (res != TRI_ERROR_NO_ERROR) {
_collection = 0;
return res;
}
LOGGER_TRACE << "using collection " << _collectionName;
assert(_collection->_collection != 0);
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add all collections to the transaction (only one)
////////////////////////////////////////////////////////////////////////////////
int addCollections () {
if (this->isEmbedded()) {
assert(_collection == 0);
_collection = TRI_CheckCollectionTransaction(this->_trx, _collectionName.c_str(), type());
if (_collection == 0) {
return TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION;
}
return TRI_ERROR_NO_ERROR;
}
else {
assert(_collection != 0);
int res = TRI_AddCollectionTransaction(this->_trx, _collectionName.c_str(), type(), _collection);
return res;
}
}
////////////////////////////////////////////////////////////////////////////////
@ -207,8 +123,8 @@ namespace triagens {
/// @brief return the name of the underlying collection
////////////////////////////////////////////////////////////////////////////////
inline string collectionName () {
return _collectionName;
const string collectionName () const {
return _name;
}
////////////////////////////////////////////////////////////////////////////////
@ -216,6 +132,12 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
inline TRI_primary_collection_t* primaryCollection () {
if (_collection == 0) {
const vector<TransactionCollection*> collections = this->_collections->getCollections();
_collection = TRI_GetCollectionTransaction(this->_trx, collections[0]->getName().c_str());
}
assert(_collection != 0);
assert(_collection->_collection != 0);
return _collection->_collection;
}
@ -240,7 +162,11 @@ namespace triagens {
/// @brief get the underlying collection's id
////////////////////////////////////////////////////////////////////////////////
inline TRI_voc_cid_t cid () const {
inline TRI_voc_cid_t cid () {
if (_collection == 0) {
_collection = TRI_GetCollectionTransaction(this->_trx, this->collectionName().c_str());
}
assert(_collection != 0);
return _collection->_cid;
}
@ -283,43 +209,6 @@ namespace triagens {
/// @}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief release the underlying collection
////////////////////////////////////////////////////////////////////////////////
int releaseCollection () {
// unuse underlying collection
if (_collection != 0) {
TRI_ReleaseCollectionVocBase(this->_vocbase, _collection);
_collection = 0;
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the transaction type
////////////////////////////////////////////////////////////////////////////////
inline TRI_transaction_type_e type () const {
return _type;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
@ -332,28 +221,10 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief name of the collection that is worked on
/// @brief name of the collection used
////////////////////////////////////////////////////////////////////////////////
const string _collectionName;
////////////////////////////////////////////////////////////////////////////////
/// @brief the type of the collection
////////////////////////////////////////////////////////////////////////////////
const TRI_col_type_e _collectionType;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not to create the collection
////////////////////////////////////////////////////////////////////////////////
const bool _createCollection;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction type (READ | WRITE)
////////////////////////////////////////////////////////////////////////////////
const TRI_transaction_type_e _type;
string _name;
////////////////////////////////////////////////////////////////////////////////
/// @brief data structure for the single collection used

View File

@ -70,11 +70,33 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
SingleCollectionWriteTransaction (TRI_vocbase_t* const vocbase,
const string& collectionName,
const TRI_col_type_e collectionType,
const bool createCollection,
const string& trxName) :
SingleCollectionTransaction<T>(vocbase, collectionName, collectionType, createCollection, trxName, TRI_TRANSACTION_WRITE),
const string& name) :
SingleCollectionTransaction<T>(vocbase, name, TRI_TRANSACTION_WRITE),
_numWrites(0),
_synchronous(false) {
if (N == 1) {
this->addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION);
}
}
SingleCollectionWriteTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const TRI_col_type_e createType) :
SingleCollectionTransaction<T>(vocbase, name, TRI_TRANSACTION_WRITE, createType),
_numWrites(0),
_synchronous(false) {
if (N == 1) {
this->addHint(TRI_TRANSACTION_HINT_SINGLE_OPERATION);
}
}
SingleCollectionWriteTransaction (TRI_vocbase_t* const vocbase,
const string& name,
const bool create,
const TRI_col_type_e createType) :
SingleCollectionTransaction<T>(vocbase, name, TRI_TRANSACTION_WRITE, create, createType),
_numWrites(0),
_synchronous(false) {

View File

@ -35,13 +35,24 @@
#include "Logger/Logger.h"
#include "Utils/CollectionReadLock.h"
#include "Utils/CollectionWriteLock.h"
#include "Utils/TransactionCollectionsList.h"
#include "Utils/TransactionCollection.h"
#if TRI_ENABLE_TRX
//#define TRX_LOG LOGGER_INFO << __FUNCTION__ << ":" << __LINE__ << " "
#define TRX_LOG if (false) std::cout
#else
#define TRX_LOG if (false) std::cout
#endif
namespace triagens {
namespace arango {
// -----------------------------------------------------------------------------
// --SECTION-- class Transaction
// -----------------------------------------------------------------------------
template<typename T>
class Transaction : public T {
@ -79,22 +90,27 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
Transaction (TRI_vocbase_t* const vocbase,
const string& trxName) :
TransactionCollectionsList* collections) :
T(),
_vocbase(vocbase),
_trxName(trxName),
_collections(collections),
_hints(0),
_setupError(TRI_ERROR_NO_ERROR) {
assert(_vocbase != 0);
int res = createTransaction();
if (res != TRI_ERROR_NO_ERROR) {
this->_setupError = res;
assert(_vocbase != 0);
TRX_LOG << "creating transaction";
int res = _collections->getError();
if (res == TRI_ERROR_NO_ERROR) {
res = createTransaction();
}
#ifdef TRI_ENABLE_TRX
// LOGGER_INFO << "created transaction " << this->_trxName;
#endif
if (res != TRI_ERROR_NO_ERROR) {
// setting up the transaction failed
TRX_LOG << "creating transaction failed";
this->_setupError = res;
}
}
////////////////////////////////////////////////////////////////////////////////
@ -102,11 +118,17 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
virtual ~Transaction () {
freeTransaction();
#ifdef TRI_ENABLE_TRX
// LOGGER_INFO << "destroyed transaction " << this->_trxName;
#endif
TRX_LOG << "destroying transaction";
if (this->_trx != 0 && ! this->isEmbedded()) {
if (this->status() == TRI_TRANSACTION_RUNNING) {
// auto abort
this->abort();
}
freeTransaction();
}
delete _collections;
}
////////////////////////////////////////////////////////////////////////////////
@ -129,6 +151,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
int begin () {
TRX_LOG << "beginning transaction";
if (this->_setupError != TRI_ERROR_NO_ERROR) {
return this->_setupError;
}
@ -140,25 +163,23 @@ namespace triagens {
int res;
if (this->isEmbedded()) {
res = addCollections();
res = this->checkCollections();
return res;
}
// ! this->isEmbedded()
if (status() != TRI_TRANSACTION_CREATED) {
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
// register usage of the underlying collections
res = useCollections();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
res = addCollections();
res = this->addCollections();
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
TRX_LOG << "calling transaction start";
return TRI_StartTransaction(this->_trx, _hints);
}
@ -167,21 +188,28 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
int commit () {
if (this->_trx == 0 || status() != TRI_TRANSACTION_RUNNING) {
// not created or not running
TRX_LOG << "committing transaction";
if (this->_trx == 0 || this->status() != TRI_TRANSACTION_RUNNING) {
// transaction not created or not running
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
if (this->isEmbedded()) {
// return instantly if the transaction is embedded
return TRI_ERROR_NO_ERROR;
}
int res;
if (this->_trx->_type == TRI_TRANSACTION_READ) {
// a read transaction just finishes
TRX_LOG << "commit - finishing read transaction";
res = TRI_FinishTransaction(this->_trx);
}
else {
// a write transaction commits
TRX_LOG << "commit - committing write transaction";
res = TRI_CommitTransaction(this->_trx);
}
@ -193,12 +221,13 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
int abort () {
TRX_LOG << "aborting transaction";
if (this->_trx == 0) {
// transaction not created
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
if (status() != TRI_TRANSACTION_RUNNING) {
if (this->status() != TRI_TRANSACTION_RUNNING) {
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
@ -217,14 +246,14 @@ namespace triagens {
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
if (status() != TRI_TRANSACTION_RUNNING) {
if (this->status() != TRI_TRANSACTION_RUNNING) {
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
int res;
if (errorNumber == TRI_ERROR_NO_ERROR) {
// there was no previous error, so we'll commit
res = commit();
res = this->commit();
}
else {
// there was a previous error, so we'll abort
@ -236,14 +265,6 @@ namespace triagens {
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief return the name of the transaction
////////////////////////////////////////////////////////////////////////////////
inline string name () const {
return this->_trxName;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the "vocbase"
////////////////////////////////////////////////////////////////////////////////
@ -574,33 +595,6 @@ namespace triagens {
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- virtual protected methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
protected:
////////////////////////////////////////////////////////////////////////////////
/// @brief use all collection
////////////////////////////////////////////////////////////////////////////////
virtual int useCollections () = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief add all collections to the transaction
////////////////////////////////////////////////////////////////////////////////
virtual int addCollections () = 0;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
@ -612,6 +606,64 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief check all collections to the transaction
///
/// this method is called in case the transaction is embedded. its purpose is
/// to validate if all collections have been previously registered in the
/// current transaction
////////////////////////////////////////////////////////////////////////////////
int checkCollections () {
assert(this->isEmbedded());
TRX_LOG << "checking collections";
const vector<TransactionCollection*>& collections = _collections->getCollections();
for (size_t i = 0; i < collections.size(); ++i) {
TransactionCollection* c = collections[i];
TRI_vocbase_col_t* collection = TRI_CheckCollectionTransaction(this->_trx, c->getName().c_str(), c->getAccessType());
if (collection == 0) {
return TRI_ERROR_TRANSACTION_UNREGISTERED_COLLECTION;
}
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add all collections to the transaction
///
/// this method is called in case the transaction is not embedded. its purpose is
/// to validate if all collections have been previously registered in the
/// current transaction
////////////////////////////////////////////////////////////////////////////////
int addCollections () {
assert(! this->isEmbedded());
TRX_LOG << "adding collections";
const vector<TransactionCollection*>& collections = _collections->getCollections();
for (size_t i = 0; i < collections.size(); ++i) {
TransactionCollection* c = collections[i];
TRX_LOG << "adding collection " << c->getName();
int res = TRI_AddCollectionTransaction(this->_trx, c->getName().c_str(), c->getAccessType());
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
}
TRX_LOG << "all collections added";
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief create transaction
////////////////////////////////////////////////////////////////////////////////
@ -622,12 +674,20 @@ namespace triagens {
return TRI_ERROR_TRANSACTION_NESTED;
}
TRX_LOG << "creating embedded transaction";
this->_trx = this->getParent();
if (this->_trx == 0) {
TRX_LOG << "creating embedded transaction failed";
return TRI_ERROR_TRANSACTION_INVALID_STATE;
}
return TRI_ERROR_NO_ERROR;
}
TRX_LOG << "creating standalone transaction";
this->_trx = TRI_CreateTransaction(_vocbase->_transactionContext, TRI_TRANSACTION_READ_REPEATABLE);
if (this->_trx == 0) {
return TRI_ERROR_OUT_OF_MEMORY;
}
@ -642,9 +702,9 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
int freeTransaction () {
if (this->isEmbedded()) {
return TRI_ERROR_NO_ERROR;
}
assert(! this->isEmbedded());
TRX_LOG << "freeing standalone transaction";
if (this->_trx != 0) {
this->unregisterTransaction();
@ -677,6 +737,12 @@ namespace triagens {
TRI_vocbase_t* const _vocbase;
////////////////////////////////////////////////////////////////////////////////
/// @brief the collections participating in the transaction
////////////////////////////////////////////////////////////////////////////////
TransactionCollectionsList* _collections;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -692,12 +758,6 @@ namespace triagens {
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction name
////////////////////////////////////////////////////////////////////////////////
string _trxName;
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction hints
////////////////////////////////////////////////////////////////////////////////
@ -709,7 +769,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
int _setupError;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,101 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction collection wrapper
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-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 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_UTILS_TRANSACTION_COLLECTION_H
#define TRIAGENS_UTILS_TRANSACTION_COLLECTION_H 1
#include "Basics/Common.h"
#include "VocBase/collection.h"
#include "VocBase/transaction.h"
namespace triagens {
namespace arango {
class TransactionCollection {
private:
TransactionCollection (const TransactionCollection&);
TransactionCollection& operator= (const TransactionCollection&);
public:
TransactionCollection (const string& name, TRI_transaction_type_e accessType) :
_name(name),
_accessType(accessType),
_createType(TRI_COL_TYPE_DOCUMENT),
_create(false) {
}
TransactionCollection (const string& name, TRI_col_type_e createType) :
_name(name),
_accessType(TRI_TRANSACTION_WRITE),
_createType(TRI_COL_TYPE_DOCUMENT),
_create(true) {
}
~TransactionCollection () {
}
inline const string getName () const {
return _name;
}
inline TRI_transaction_type_e getAccessType () const {
return _accessType;
}
inline void setAccessType (TRI_transaction_type_e accessType) {
_accessType = accessType;
}
inline bool getCreateFlag () const {
return _create;
}
inline TRI_col_type_e getCreateType () const {
return _createType;
}
private:
string _name;
TRI_transaction_type_e _accessType;
TRI_col_type_e _createType;
bool _create;
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -0,0 +1,195 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief transaction collections list
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2004-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 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_UTILS_TRANSACTION_COLLECTION_LIST_H
#define TRIAGENS_UTILS_TRANSACTION_COLLECTION_LIST_H 1
#include "Basics/Common.h"
#include "VocBase/collection.h"
#include "VocBase/transaction.h"
#include "VocBase/vocbase.h"
#include "Utils/TransactionCollection.h"
namespace triagens {
namespace arango {
class TransactionCollectionsList {
typedef map<string, TransactionCollection*> ListType;
private:
TransactionCollectionsList& operator= (const TransactionCollectionsList&);
TransactionCollectionsList (const TransactionCollectionsList&);
public:
TransactionCollectionsList () :
_collections() {
}
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const string& name,
TRI_transaction_type_e accessType) :
_vocbase(vocbase),
_collections(),
_error(TRI_ERROR_NO_ERROR) {
addCollection(name, accessType, false);
}
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const string& name,
TRI_transaction_type_e accessType,
const TRI_col_type_e createType) :
_vocbase(vocbase),
_collections(),
_error(TRI_ERROR_NO_ERROR) {
addCollection(name, accessType, true, createType);
}
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const string& name,
TRI_transaction_type_e accessType,
const bool create,
const TRI_col_type_e createType) :
_vocbase(vocbase),
_collections(),
_error(TRI_ERROR_NO_ERROR) {
addCollection(name, accessType, create, createType);
}
TransactionCollectionsList (TRI_vocbase_t* const vocbase,
const vector<string>& readCollections,
const vector<string>& writeCollections) :
_vocbase(vocbase),
_collections() {
for (size_t i = 0; i < readCollections.size(); ++i) {
addCollection(readCollections[i], TRI_TRANSACTION_READ, false);
}
for (size_t i = 0; i < writeCollections.size(); ++i) {
addCollection(writeCollections[i], TRI_TRANSACTION_WRITE, false);
}
}
~TransactionCollectionsList () {
ListType::iterator it;
for (it = _collections.begin(); it != _collections.end(); ++it) {
delete (*it).second;
}
_collections.clear();
}
inline int getError () const {
return _error;
}
const vector<TransactionCollection*> getCollections () {
ListType::iterator it;
vector<TransactionCollection*> collections;
for (it = _collections.begin(); it != _collections.end(); ++it) {
collections.push_back((*it).second);
}
return collections;
}
void addCollection (const string& name,
TRI_transaction_type_e type,
bool create,
TRI_col_type_e createType = TRI_COL_TYPE_DOCUMENT) {
ListType::iterator it;
string realName;
if (name.empty()) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return;
}
if (isdigit(name[0])) {
// name is passed as a string with the collection id
// look up the collection name for the id
TRI_voc_cid_t id = triagens::basics::StringUtils::uint64(name);
char* n = TRI_GetCollectionNameByIdVocBase(_vocbase, id);
if (n == 0) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return;
}
realName = string(n);
TRI_Free(TRI_UNKNOWN_MEM_ZONE, n);
}
else {
// name is passed as a "real" name
realName = name;
}
it = _collections.find(realName);
if (it != _collections.end()) {
TransactionCollection* c = (*it).second;
if (type == TRI_TRANSACTION_WRITE && type != c->getAccessType()) {
// upgrade the type
c->setAccessType(type);
}
}
else {
// check whether the collection exists. if not, create it
if (( create && TRI_FindCollectionByNameOrBearVocBase(_vocbase, realName.c_str(), createType) == NULL) ||
(! create && TRI_LookupCollectionByNameVocBase(_vocbase, realName.c_str()) == NULL)) {
_error = TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND;
return;
}
_collections[realName] = new TransactionCollection(realName, type);
}
}
private:
TRI_vocbase_t* _vocbase;
ListType _collections;
int _error;
};
}
}
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\)"
// End:

View File

@ -61,9 +61,7 @@ namespace triagens {
UserTransaction (TRI_vocbase_t* const vocbase,
const vector<string>& readCollections,
const vector<string>& writeCollections) :
Transaction<T>(vocbase, "UserTransaction"),
_readCollections(readCollections),
_writeCollections(writeCollections) {
Transaction<T>(vocbase, new TransactionCollectionsList(vocbase, readCollections, writeCollections)) {
}
////////////////////////////////////////////////////////////////////////////////
@ -71,99 +69,8 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
~UserTransaction () {
if (this->_trx != 0) {
if (this->status() == TRI_TRANSACTION_RUNNING) {
// auto abort
this->abort();
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- virtual protected functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
protected:
////////////////////////////////////////////////////////////////////////////////
/// @brief use all collections
/// this is a no op, as using is done when trx is started
////////////////////////////////////////////////////////////////////////////////
int useCollections () {
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief release all collections in use
/// this is a no op, as releasing is done when trx is finished
////////////////////////////////////////////////////////////////////////////////
int releaseCollections () {
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief add all collections to the transaction
////////////////////////////////////////////////////////////////////////////////
int addCollections () {
int res;
size_t i;
for (i = 0; i < _readCollections.size(); ++i) {
res = TRI_AddCollectionTransaction(this->_trx, _readCollections[i].c_str(), TRI_TRANSACTION_READ, 0);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
}
for (i = 0; i < _writeCollections.size(); ++i) {
res = TRI_AddCollectionTransaction(this->_trx, _writeCollections[i].c_str(), TRI_TRANSACTION_WRITE, 0);
if (res != TRI_ERROR_NO_ERROR) {
return res;
}
}
return TRI_ERROR_NO_ERROR;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDB
/// @{
////////////////////////////////////////////////////////////////////////////////
private:
////////////////////////////////////////////////////////////////////////////////
/// @brief collections that are opened in read mode
////////////////////////////////////////////////////////////////////////////////
vector<string> _readCollections;
////////////////////////////////////////////////////////////////////////////////
/// @brief collections that are opened in write mode
////////////////////////////////////////////////////////////////////////////////
vector<string> _writeCollections;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -640,15 +640,18 @@ void ApplicationV8::stop () {
////////////////////////////////////////////////////////////////////////////////
bool ApplicationV8::prepareV8Instance (const size_t i) {
static char const* files[] = { "common/bootstrap/modules.js",
"common/bootstrap/monkeypatches.js",
"common/bootstrap/print.js",
"common/bootstrap/errors.js",
"server/ahuacatl.js",
"server/server.js",
"server/ArangoCollection.js",
"server/ArangoStructure.js"
};
vector<string> files;
files.push_back("common/bootstrap/modules.js");
files.push_back("common/bootstrap/module-internal.js");
files.push_back("common/bootstrap/module-fs.js");
files.push_back("common/bootstrap/module-console.js");
files.push_back("common/bootstrap/monkeypatches.js");
files.push_back("common/bootstrap/errors.js");
files.push_back("server/ahuacatl.js");
files.push_back("server/server.js");
files.push_back("server/ArangoCollection.js");
files.push_back("server/ArangoStructure.js");
LOGGER_TRACE << "initialising V8 context #" << i;
@ -687,7 +690,7 @@ bool ApplicationV8::prepareV8Instance (const size_t i) {
TRI_InitV8Shell(context->_context);
// load all init files
for (size_t j = 0; j < sizeof(files) / sizeof(files[0]); ++j) {
for (size_t j = 0; j < files.size(); ++j) {
bool ok = _startupLoader.loadScript(context->_context, files[j]);
if (! ok) {

View File

@ -416,7 +416,7 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
collection = TRI_LookupCollectionByIdVocBase(vocbase, TRI_UInt64String(v.c_str()));
}
else {
collection = TRI_FindCollectionByNameVocBase(vocbase, v.c_str(), false);
collection = TRI_LookupCollectionByNameVocBase(vocbase, v.c_str());
}
if (collection != 0) {
@ -428,7 +428,7 @@ static HttpResponse* ExecuteActionVocbase (TRI_vocbase_t* vocbase,
}
case TRI_ACT_COLLECTION_NAME: {
TRI_vocbase_col_t const* collection = TRI_FindCollectionByNameVocBase(vocbase, v.c_str(), false);
TRI_vocbase_col_t const* collection = TRI_LookupCollectionByNameVocBase(vocbase, v.c_str());
if (collection != 0) {
valuesObject->Set(v8::String::New(k.c_str()), TRI_WrapCollection(collection));

View File

@ -1741,7 +1741,7 @@ static v8::Handle<v8::Value> JS_AllQuery (v8::Arguments const& argv) {
uint32_t total = 0;
vector<TRI_doc_mptr_t*> docs;
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {

View File

@ -764,7 +764,7 @@ static v8::Handle<v8::Value> DocumentVocbaseCol (const bool useCollection,
assert(key);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type);
SingleCollectionReadOnlyTransaction<EmbeddableTransaction<V8TransactionContext> > trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot fetch document", true)));
@ -849,7 +849,7 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (const bool useCollection,
assert(key);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type, false, "ReplaceVocbase");
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot replace document", true)));
@ -903,11 +903,11 @@ static v8::Handle<v8::Value> ReplaceVocbaseCol (const bool useCollection,
/// above. The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document creation operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// Thus, the @FA{waitForSync} parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -984,11 +984,11 @@ static v8::Handle<v8::Value> SaveVocbaseCol (SingleCollectionWriteTransaction<Em
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document creation operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// Thus, the @FA{waitForSync} parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -1155,7 +1155,7 @@ static v8::Handle<v8::Value> UpdateVocbaseCol (const bool useCollection,
}
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type, false, "UpdateVocbase");
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot update document", true)));
@ -1256,7 +1256,7 @@ static v8::Handle<v8::Value> RemoveVocbaseCol (const bool useCollection,
assert(key);
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type, false, "DeleteVocbase");
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot delete document", true)));
@ -3311,10 +3311,7 @@ static v8::Handle<v8::Value> JS_DatafilesVocbaseCol (v8::Arguments const& argv)
/// An error is thrown if there @LIT{_rev} does not longer match the current
/// revision of the document.
///
/// An error is thrown if the document does not exist.
///
/// The document must be part of the @FA{collection}; otherwise, an error
/// is thrown.
/// An error is also thrown if the document does not exist.
///
/// @FUN{@FA{collection}.document(@FA{document-handle})}
///
@ -3325,15 +3322,30 @@ static v8::Handle<v8::Value> JS_DatafilesVocbaseCol (v8::Arguments const& argv)
///
/// Returns the document for a document-handle:
///
/// @TINYEXAMPLE{shell-read-document,read document from a collection}
/// @code
/// arango> db.example.document("1432124/2873916");
/// { "_id" : "1432124/2873916", "_rev" : 2873916, "Hallo" : "World" }
/// @endcode
///
/// An error is raised if the document is unknown:
///
/// @TINYEXAMPLE{shell-read-document-not-found,unknown handle}
/// @code
/// arango> db.example.document("1432124/123456");
/// JavaScript exception in file '(arango)' at 1,12:
/// [ArangoError 1202: document not found: document not found]
/// !db.example.document("1432124/123456");
/// ! ^
/// @endcode
///
/// An error is raised if the handle is invalid:
///
/// @TINYEXAMPLE{shell-read-document-bad-handle,invalid handle}
/// @code
/// arango> db.example.document("12345");
/// JavaScript exception in file '(arango)' at 1,12:
/// [ArangoError 10: bad parameter: <document-identifier> must be a document identifier]
/// !db.example.document("12345");
/// ! ^
/// @endcode
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_DocumentVocbaseCol (v8::Arguments const& argv) {
@ -4462,6 +4474,7 @@ static v8::Handle<v8::Value> JS_NameVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(v8::String::New("illegal collection pointer")));
}
// TODO: protect this against race conditions (parallel rename operation)
return scope.Close(v8::String::New(collection->_name));
}
@ -4624,29 +4637,29 @@ static v8::Handle<v8::Value> JS_PropertiesVocbaseCol (v8::Arguments const& argv)
}
////////////////////////////////////////////////////////////////////////////////
/// @brief deletes a document
/// @brief removes a document
///
/// @FUN{@FA{collection}.remove(@FA{document})}
///
/// Deletes a document. If there is revision mismatch, then an error is thrown.
/// Removes a document. If there is revision mismatch, then an error is thrown.
///
/// @FUN{@FA{collection}.remove(@FA{document}, true)}
///
/// Deletes a document. If there is revision mismatch, then mismatch
/// is ignored and document is deleted. The function returns
/// @LIT{true} if the document existed and was deleted. It returns
/// @LIT{false}, if the document was already deleted.
/// Removes a document. If there is revision mismatch, then mismatch is ignored
/// and document is deleted. The function returns @LIT{true} if the document
/// existed and was deleted. It returns @LIT{false}, if the document was already
/// deleted.
///
/// @FUN{@FA{collection}.remove(@FA{document}, true, @FA{waitForSync})}
///
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document deletion operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// The optional @FA{waitForSync} parameter can be used to force synchronisation
/// of the document deletion operation to disk even in case that the
/// @LIT{waitForSync} flag had been disabled for the entire collection. Thus,
/// the @FA{waitForSync} parameter can be used to force synchronisation of just
/// specific operations. To use this, set the @FA{waitForSync} parameter to
/// @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -4657,13 +4670,39 @@ static v8::Handle<v8::Value> JS_PropertiesVocbaseCol (v8::Arguments const& argv)
///
/// @EXAMPLES
///
/// Delete a document:
/// Remove a document:
///
/// @TINYEXAMPLE{shell_remove-document,delete a document}
/// @code
/// arango> a1 = db.example.save({ a : 1 });
/// { "_id" : "116308/3449537", "_rev" : 3449537 }
/// arango> db.example.document(a1);
/// { "_id" : "116308/3449537", "_rev" : 3449537, "a" : 1 }
/// arango> db.example.remove(a1);
/// true
/// arango> db.example.document(a1);
/// JavaScript exception in file '(arango)' at 1,12: [ArangoError 1202: document not found: document not found]
/// !db.example.document(a1);
/// ! ^
/// @endcode
///
/// Delete a document with a conflict:
/// Remove a document with a conflict:
///
/// @TINYEXAMPLE{shell_remove-document-conflict,delete a document}
/// @code
/// arango> a1 = db.example.save({ a : 1 });
/// { "_id" : "116308/3857139", "_rev" : 3857139 }
/// arango> a2 = db.example.replace(a1, { a : 2 });
/// { "_id" : "116308/3857139", "_rev" : 3922675, "_oldRev" : 3857139 }
/// arango> db.example.remove(a1);
/// JavaScript exception in file '(arango)' at 1,18: [ArangoError 1200: conflict: cannot remove document]
/// !db.example.remove(a1);
/// ! ^
/// arango> db.example.remove(a1, true);
/// true
/// arango> db.example.document(a1);
/// JavaScript exception in file '(arango)' at 1,12: [ArangoError 1202: document not found: document not found]
/// !db.example.document(a1);
/// ! ^
/// @endcode
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_RemoveVocbaseCol (v8::Arguments const& argv) {
@ -4743,11 +4782,11 @@ static v8::Handle<v8::Value> JS_RenameVocbaseCol (v8::Arguments const& argv) {
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document replacement operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// Thus, the @FA{waitForSync} parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -4789,11 +4828,11 @@ static v8::Handle<v8::Value> JS_ReplaceVocbaseCol (v8::Arguments const& argv) {
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document update operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// Thus, the @FA{waitForSync} parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -4854,7 +4893,7 @@ static v8::Handle<v8::Value> JS_SaveVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_INTERNAL)));
}
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type, false, "SaveVocbase");
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, 1> trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
@ -4946,6 +4985,37 @@ static v8::Handle<v8::Value> JS_StatusVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::Number::New((int) status));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the revision id of a collection
/// the revision id is updated when the document data in a collection changes
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_RevisionVocbaseCol (v8::Arguments const& argv) {
v8::HandleScope scope;
v8::Handle<v8::Object> err;
TRI_vocbase_col_t const* collection = UseCollection(argv.Holder(), &err);
if (collection == 0) {
return scope.Close(v8::ThrowException(err));
}
TRI_primary_collection_t* primary = collection->_collection;
if (! TRI_IS_DOCUMENT_COLLECTION(collection->_type)) {
TRI_ReleaseCollection(collection);
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_INTERNAL, "unknown collection type")));
}
primary->beginRead(primary);
TRI_voc_rid_t rid = primary->base._info._rid;
primary->endRead(primary);
TRI_ReleaseCollection(collection);
return scope.Close(v8::Number::New(rid));
}
////////////////////////////////////////////////////////////////////////////////
/// @brief truncates a collection
////////////////////////////////////////////////////////////////////////////////
@ -4960,7 +5030,7 @@ static v8::Handle<v8::Value> JS_TruncateVocbaseCol (v8::Arguments const& argv) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(TRI_ERROR_INTERNAL)));
}
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, UINT64_MAX> trx(col->_vocbase, col->_name, (TRI_col_type_e) col->_type, false, "TruncateVocbase");
SingleCollectionWriteTransaction<EmbeddableTransaction<V8TransactionContext>, UINT64_MAX> trx(col->_vocbase, col->_name);
int res = trx.begin();
if (res != TRI_ERROR_NO_ERROR) {
return scope.Close(v8::ThrowException(TRI_CreateErrorObject(res, "cannot truncate collection", true)));
@ -5160,12 +5230,7 @@ static v8::Handle<v8::Value> MapGetVocBase (v8::Local<v8::String> name,
// look up the value if it exists
TRI_vocbase_col_t const* collection;
if (collectionType == TRI_COL_TYPE_EDGE) {
collection = TRI_FindEdgeCollectionByNameVocBase(vocbase, key.c_str(), true);
}
else {
collection = TRI_FindDocumentCollectionByNameVocBase(vocbase, key.c_str(), true);
}
collection = TRI_FindCollectionByNameOrBearVocBase(vocbase, key.c_str(), (TRI_col_type_t) collectionType);
// if the key is not present return an empty handle as signal
if (collection == 0) {
@ -5247,7 +5312,7 @@ static v8::Handle<v8::Value> JS_CollectionVocbase (v8::Arguments const& argv) {
else {
string name = TRI_ObjectToString(val);
collection = TRI_FindCollectionByNameVocBase(vocbase, name.c_str(), false);
collection = TRI_LookupCollectionByNameVocBase(vocbase, name.c_str());
}
if (collection == 0) {
@ -5345,7 +5410,7 @@ static v8::Handle<v8::Value> JS_CompletionsVocbase (v8::Arguments const& argv) {
///
/// @FUN{db._create(@FA{collection-name}, @FA{properties})}
///
/// @FA{properties} must be an object, with the following attribues:
/// @FA{properties} must be an object with the following attributes:
///
/// - @LIT{waitForSync} (optional, default @LIT{false}): If @LIT{true} creating
/// a document will only return after the data was synced to disk.
@ -5415,7 +5480,7 @@ static v8::Handle<v8::Value> JS_CreateDocumentCollectionVocbase (v8::Arguments c
///
/// @FUN{db._createEdgeCollection(@FA{collection-name}, @FA{properties})}
///
/// @FA{properties} must be an object, with the following attribues:
/// @FA{properties} must be an object with the following attributes:
///
/// - @LIT{waitForSync} (optional, default @LIT{false}): If @LIT{true} creating
/// a document will only return after the data was synced to disk.
@ -5435,46 +5500,72 @@ static v8::Handle<v8::Value> JS_CreateEdgeCollectionVocbase (v8::Arguments const
}
////////////////////////////////////////////////////////////////////////////////
/// @brief deletes a document
/// @brief removes a document
///
/// @FUN{@FA{db}._remove(@FA{document})}
///
/// Deletes a document. If there is revision mismatch, then an error is thrown.
/// Removes a document. If there is revision mismatch, then an error is thrown.
///
/// @FUN{@FA{db}._remove(@FA{document}, true)}
///
/// Deletes a document. If there is revision mismatch, then mismatch
/// is ignored and document is deleted. The function returns
/// @LIT{true} if the document existed and was deleted. It returns
/// @LIT{false}, if the document was already deleted.
/// Removes a document. If there is revision mismatch, then mismatch is ignored
/// and document is deleted. The function returns @LIT{true} if the document
/// existed and was deleted. It returns @LIT{false}, if the document was already
/// deleted.
///
/// @FUN{@FA{db}._remove(@FA{document}, true, @FA{waitForSync})}
///
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document deletion operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// The optional @FA{waitForSync} parameter can be used to force synchronisation
/// of the document deletion operation to disk even in case that the
/// @LIT{waitForSync} flag had been disabled for the entire collection. Thus,
/// the @FA{waitForSync} parameter can be used to force synchronisation of just
/// specific operations. To use this, set the @FA{waitForSync} parameter to
/// @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
/// @FUN{@FA{db}._remove(@FA{document-handle}, @FA{data})}
///
/// As before. Instead of document a @FA{document-handle} can be passed as
/// first argument.
/// As before. Instead of document a @FA{document-handle} can be passed as first
/// argument.
///
/// @EXAMPLES
///
/// Delete a document:
/// Remove a document:
///
/// @TINYEXAMPLE{shell_remove-document-db,delete a document}
/// @code
/// arango> a1 = db.example.save({ a : 1 });
/// { "_id" : "116308/4214943", "_rev" : 4214943 }
/// arango> db._remove(a1);
/// true
/// arango> db._remove(a1);
/// JavaScript exception in file '(arango)' at 1,4: [ArangoError 1202: document not found: cannot remove document]
/// !db._remove(a1);
/// ! ^
/// arango> db._remove(a1, true);
/// false
/// @endcode
///
/// Delete a document with a conflict:
/// Remove a document with a conflict:
///
/// @TINYEXAMPLE{shell_remove-document-conflict-db,delete a document}
/// @code
/// arango> a1 = db.example.save({ a : 1 });
/// { "_id" : "116308/4042634", "_rev" : 4042634 }
/// arango> a2 = db._replace(a1, { a : 2 });
/// { "_id" : "116308/4042634", "_rev" : 4108170, "_oldRev" : 4042634 }
/// arango> db._delete(a1);
/// JavaScript exception in file '(arango)' at 1,4: [ArangoError 1200: conflict: cannot delete document]
/// !db._delete(a1);
/// ! ^
/// arango> db._delete(a1, true);
/// true
/// arango> db._document(a1);
/// JavaScript exception in file '(arango)' at 1,4: [ArangoError 1202: document not found: document not found]
/// !db._document(a1);
/// ! ^
/// @endcode
////////////////////////////////////////////////////////////////////////////////
static v8::Handle<v8::Value> JS_RemoveVocbase (v8::Arguments const& argv) {
@ -5534,11 +5625,11 @@ static v8::Handle<v8::Value> JS_DocumentVocbase (v8::Arguments const& argv) {
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document replacement operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// Thus, the @FA{waitForSync} parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -5576,11 +5667,11 @@ static v8::Handle<v8::Value> JS_ReplaceVocbase (v8::Arguments const& argv) {
/// The optional @FA{waitForSync} parameter can be used to force
/// synchronisation of the document update operation to disk even in case
/// that the @LIT{waitForSync} flag had been disabled for the entire collection.
/// Thus, the @FA{waitForSync} URL parameter can be used to force synchronisation
/// Thus, the @FA{waitForSync} parameter can be used to force synchronisation
/// of just specific operations. To use this, set the @FA{waitForSync} parameter
/// to @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} URL parameter cannot be used to disable
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
@ -6209,6 +6300,7 @@ v8::Handle<v8::Value> TRI_WrapShapedJson (TRI_vocbase_col_t const* collection,
// store the document reference
TRI_voc_rid_t rid = document->_rid;
// TODO: protect this against race conditions (parallel rename)
result->Set(v8g->DidKey, DocumentId(collection->_name, document->_key), v8::ReadOnly);
result->Set(v8g->RevKey, v8::Number::New(rid), v8::ReadOnly);
result->Set(v8g->KeyKey, v8::String::New(document->_key), v8::ReadOnly);
@ -6440,6 +6532,7 @@ TRI_v8_global_t* TRI_InitV8VocBridge (v8::Handle<v8::Context> context,
TRI_AddMethodVocbase(rt, "name", JS_NameVocbaseCol);
TRI_AddMethodVocbase(rt, "properties", JS_PropertiesVocbaseCol);
TRI_AddMethodVocbase(rt, "remove", JS_RemoveVocbaseCol);
TRI_AddMethodVocbase(rt, "revision", JS_RevisionVocbaseCol);
TRI_AddMethodVocbase(rt, "rename", JS_RenameVocbaseCol);
TRI_AddMethodVocbase(rt, "setAttribute", JS_SetAttributeVocbaseCol, true);
TRI_AddMethodVocbase(rt, "status", JS_StatusVocbaseCol);

View File

@ -482,14 +482,15 @@ void TRI_InitCollectionInfo (TRI_vocbase_t* vocbase,
assert(parameter);
memset(parameter, 0, sizeof(TRI_col_info_t));
parameter->_version = TRI_COL_VERSION;
parameter->_type = type;
parameter->_cid = 0;
parameter->_version = TRI_COL_VERSION;
parameter->_type = type;
parameter->_cid = 0;
parameter->_rid = 0;
parameter->_deleted = false;
parameter->_isVolatile = false;
parameter->_isSystem = false;
parameter->_maximalSize = (maximalSize / PageSize) * PageSize;
parameter->_deleted = false;
parameter->_isVolatile = false;
parameter->_isSystem = false;
parameter->_maximalSize = (maximalSize / PageSize) * PageSize;
if (parameter->_maximalSize == 0 && maximalSize != 0) {
parameter->_maximalSize = PageSize;
}
@ -501,7 +502,7 @@ void TRI_InitCollectionInfo (TRI_vocbase_t* vocbase,
parameter->_options = options;
}
else {
parameter->_options = 0;
parameter->_options = NULL;
}
}
@ -513,13 +514,14 @@ void TRI_CopyCollectionInfo (TRI_col_info_t* dst, TRI_col_info_t* src) {
assert(dst);
memset(dst, 0, sizeof(TRI_col_info_t));
dst->_version = src->_version;
dst->_type = src->_type;
dst->_cid = src->_cid;
dst->_version = src->_version;
dst->_type = src->_type;
dst->_cid = src->_cid;
dst->_rid = src->_rid;
dst->_deleted = src->_deleted;
dst->_isSystem = src->_isSystem;
dst->_isVolatile = src->_isVolatile;
dst->_deleted = src->_deleted;
dst->_isSystem = src->_isSystem;
dst->_isVolatile = src->_isVolatile;
dst->_maximalSize = src->_maximalSize;
TRI_CopyString(dst->_name, src->_name, sizeof(dst->_name));
dst->_waitForSync = src->_waitForSync;
@ -528,7 +530,7 @@ void TRI_CopyCollectionInfo (TRI_col_info_t* dst, TRI_col_info_t* src) {
dst->_options = TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, src->_options);
}
else {
dst->_options = 0;
dst->_options = NULL;
}
}
@ -539,7 +541,7 @@ void TRI_CopyCollectionInfo (TRI_col_info_t* dst, TRI_col_info_t* src) {
void TRI_FreeCollectionInfoOptions (TRI_col_info_t* parameter) {
if (parameter->_options) {
TRI_FreeJson(TRI_UNKNOWN_MEM_ZONE, parameter->_options);
parameter->_options = 0;
parameter->_options = NULL;
}
}

View File

@ -218,10 +218,11 @@ typedef struct TRI_col_info_s {
TRI_col_version_t _version; // collection version
TRI_col_type_e _type; // collection type
TRI_voc_cid_t _cid; // collection identifier
struct TRI_json_s* _options; // optional collection options
TRI_voc_rid_t _rid; // last revision id
TRI_voc_size_t _maximalSize; // maximal size of memory mapped file
char _name[TRI_COL_PATH_LENGTH]; // name of the collection
struct TRI_json_s* _options; // optional collection options
// flags
bool _deleted : 1; // if true, collection has been deleted
@ -250,7 +251,7 @@ typedef struct TRI_collection_s {
TRI_vector_pointer_t _datafiles; // all datafiles
TRI_vector_pointer_t _journals; // all journals
TRI_vector_pointer_t _compactors; // all compactor files
TRI_vector_string_t _indexFiles; // all index filenames
TRI_vector_string_t _indexFiles; // all index filenames
}
TRI_collection_t;

View File

@ -143,6 +143,19 @@ static bool IsVisible (TRI_doc_mptr_t const* header,
return (header != NULL && header->_validTo == 0);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief set the collection revision id with the marker's tick value
////////////////////////////////////////////////////////////////////////////////
static void CollectionRevisionUpdate (TRI_document_collection_t* document,
const TRI_df_marker_t* const marker) {
TRI_col_info_t* info = &document->base.base._info;
if (marker->_tick > info->_rid) {
info->_rid = marker->_tick;
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -295,6 +308,8 @@ static int WriteElement (TRI_document_collection_t* document,
return res;
}
CollectionRevisionUpdate(document, marker);
TRI_LOCK_JOURNAL_ENTRIES_DOC_COLLECTION(document);
journal->_written = ((char*) result) + marker->_size;
@ -1437,6 +1452,8 @@ static bool OpenIterator (TRI_df_marker_t const* marker, void* data, TRI_datafil
primary = &collection->base;
CollectionRevisionUpdate(collection, marker);
// new or updated document
if (marker->_type == TRI_DOC_MARKER_KEY_EDGE ||
marker->_type == TRI_DOC_MARKER_KEY_DOCUMENT) {

View File

@ -505,8 +505,7 @@ void TRI_DumpTransactionContext (TRI_transaction_context_t* const context) {
////////////////////////////////////////////////////////////////////////////////
static TRI_transaction_collection_t* CreateCollection (const char* const name,
const TRI_transaction_type_e type,
TRI_vocbase_col_t* initialiser) {
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
collection = (TRI_transaction_collection_t*) TRI_Allocate(TRI_UNKNOWN_MEM_ZONE, sizeof(TRI_transaction_collection_t), false);
@ -525,10 +524,9 @@ static TRI_transaction_collection_t* CreateCollection (const char* const name,
// initialise collection properties
collection->_type = type;
collection->_collection = initialiser;
collection->_collection = NULL;
collection->_globalInstance = NULL;
collection->_locked = false;
collection->_externalLock = (initialiser != NULL);
// initialise private copy of write transactions list
InitTransactionList(&collection->_writeTransactions);
@ -595,10 +593,8 @@ static int AcquireCollectionLocks (TRI_transaction_t* const trx) {
for (i = 0; i < n; ++i) {
TRI_transaction_collection_t* collection;
collection = TRI_AtVectorPointer(&trx->_collections, i);
if (! collection->_externalLock) {
collection->_collection = TRI_UseCollectionByNameVocBase(trx->_context->_vocbase, collection->_name);
}
collection = (TRI_transaction_collection_t*) TRI_AtVectorPointer(&trx->_collections, i);
collection->_collection = TRI_UseCollectionByNameVocBase(trx->_context->_vocbase, collection->_name);
if (collection->_collection == NULL) {
return TRI_errno();
@ -655,9 +651,7 @@ static int ReleaseCollectionLocks (TRI_transaction_t* const trx) {
}
// unuse collection
if (! collection->_externalLock) {
TRI_ReleaseCollectionVocBase(trx->_context->_vocbase, collection->_collection);
}
TRI_ReleaseCollectionVocBase(trx->_context->_vocbase, collection->_collection);
collection->_collection = NULL;
}
@ -1091,8 +1085,7 @@ TRI_vocbase_col_t* TRI_CheckCollectionTransaction (TRI_transaction_t* const trx,
int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
const char* const name,
const TRI_transaction_type_e type,
TRI_vocbase_col_t* initialiser) {
const TRI_transaction_type_e type) {
TRI_transaction_collection_t* collection;
size_t i, n;
@ -1116,7 +1109,7 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
if (res < 0) {
// collection is not contained in vector
collection = CreateCollection(name, type, initialiser);
collection = CreateCollection(name, type);
if (collection == NULL) {
// out of memory
return TRI_ERROR_OUT_OF_MEMORY;
@ -1139,7 +1132,7 @@ int TRI_AddCollectionTransaction (TRI_transaction_t* const trx,
}
// collection was not contained. now insert it
collection = CreateCollection(name, type, initialiser);
collection = CreateCollection(name, type);
if (collection == NULL) {
// out of memory
return TRI_ERROR_OUT_OF_MEMORY;
@ -1240,6 +1233,30 @@ int TRI_FinishTransaction (TRI_transaction_t* const trx) {
return res;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get the pointer to a collection after it has been initialised
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_GetCollectionTransaction (const TRI_transaction_t* const trx,
const char* const name) {
size_t i, n;
assert(trx->_status == TRI_TRANSACTION_RUNNING);
n = trx->_collections._length;
// process collections in forward order
for (i = 0; i < n; ++i) {
TRI_transaction_collection_t* collection;
collection = (TRI_transaction_collection_t*) TRI_AtVectorPointer(&trx->_collections, i);
if (TRI_EqualString(name, collection->_name)) {
return collection->_collection;
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -283,7 +283,6 @@ typedef struct TRI_transaction_collection_s {
struct TRI_vocbase_col_s* _collection; // vocbase collection pointer
TRI_transaction_collection_global_t* _globalInstance; // pointer to the global instance of the collection in the trx system
bool _locked; // lock flag (used for write-transactions)
bool _externalLock; // flag whether collection was locked externally
}
TRI_transaction_collection_t;
@ -395,8 +394,7 @@ struct TRI_vocbase_col_s* TRI_CheckCollectionTransaction (TRI_transaction_t* con
int TRI_AddCollectionTransaction (TRI_transaction_t* const,
const char* const,
const TRI_transaction_type_e,
struct TRI_vocbase_col_s*);
const TRI_transaction_type_e);
////////////////////////////////////////////////////////////////////////////////
/// @brief start a transaction
@ -422,6 +420,13 @@ int TRI_AbortTransaction (TRI_transaction_t* const);
int TRI_FinishTransaction (TRI_transaction_t* const);
////////////////////////////////////////////////////////////////////////////////
/// @brief get the pointer to a collection after it has been initialised
////////////////////////////////////////////////////////////////////////////////
struct TRI_vocbase_col_s* TRI_GetCollectionTransaction (const TRI_transaction_t* const,
const char* const);
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////

View File

@ -815,7 +815,6 @@ static int ManifestCollectionVocBase (TRI_vocbase_t* vocbase, TRI_vocbase_col_t*
static TRI_vocbase_col_t* FindCollectionByNameVocBase (TRI_vocbase_t* vocbase,
char const* name,
bool bear,
TRI_col_type_e type) {
union { void const* v; TRI_vocbase_col_t* c; } found;
@ -827,15 +826,9 @@ static TRI_vocbase_col_t* FindCollectionByNameVocBase (TRI_vocbase_t* vocbase,
return found.c;
}
if (! bear) {
TRI_set_errno(TRI_ERROR_ARANGO_COLLECTION_NOT_FOUND);
return NULL;
}
return BearCollectionVocBase(vocbase, name, type);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief loads an existing (document) collection
///
@ -1372,6 +1365,32 @@ TRI_vector_pointer_t TRI_CollectionsVocBase (TRI_vocbase_t* vocbase) {
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief get a collection name by a collection id
///
/// the name is fetched under a lock to make this thread-safe. returns NULL if
/// the collection does not exist
/// it is the caller's responsibility to free the name returned
////////////////////////////////////////////////////////////////////////////////
char* TRI_GetCollectionNameByIdVocBase (TRI_vocbase_t* vocbase,
const TRI_voc_cid_t id) {
union { void const* v; TRI_vocbase_col_t* c; } found;
char* name;
TRI_READ_LOCK_COLLECTIONS_VOCBASE(vocbase);
found.v = TRI_LookupByKeyAssociativePointer(&vocbase->_collectionsById, &id);
if (found.v == NULL) {
name = NULL;
}
else {
name = TRI_DuplicateStringZ(TRI_UNKNOWN_MEM_ZONE, found.c->_name);
}
TRI_READ_UNLOCK_COLLECTIONS_VOCBASE(vocbase);
return name;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a (document) collection by name
////////////////////////////////////////////////////////////////////////////////
@ -1401,27 +1420,13 @@ TRI_vocbase_col_t* TRI_LookupCollectionByIdVocBase (TRI_vocbase_t* vocbase, TRI_
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds a collection by name
/// @brief finds a collection by name, optionally creates it
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_FindCollectionByNameVocBase (TRI_vocbase_t* vocbase, char const* name, bool bear) {
return TRI_FindDocumentCollectionByNameVocBase(vocbase, name, bear);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds a primary collection by name
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_FindDocumentCollectionByNameVocBase (TRI_vocbase_t* vocbase, char const* name, bool bear) {
return FindCollectionByNameVocBase(vocbase, name, bear, TRI_COL_TYPE_DOCUMENT);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief finds an edge collection by name
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_FindEdgeCollectionByNameVocBase (TRI_vocbase_t* vocbase, char const* name, bool bear) {
return FindCollectionByNameVocBase(vocbase, name, bear, TRI_COL_TYPE_EDGE);
TRI_vocbase_col_t* TRI_FindCollectionByNameOrBearVocBase (TRI_vocbase_t* vocbase,
char const* name,
const TRI_col_type_t type) {
return FindCollectionByNameVocBase(vocbase, name, (TRI_col_type_e) type);
}
////////////////////////////////////////////////////////////////////////////////

View File

@ -505,6 +505,16 @@ void TRI_DestroyVocBase (TRI_vocbase_t*);
TRI_vector_pointer_t TRI_CollectionsVocBase (TRI_vocbase_t*);
////////////////////////////////////////////////////////////////////////////////
/// @brief get a collection name by a collection id
///
/// the name is fetched under a lock to make this thread-safe. returns NULL if
/// the collection does not exist
/// it is the caller's responsibility to free the name returned
////////////////////////////////////////////////////////////////////////////////
char* TRI_GetCollectionNameByIdVocBase (TRI_vocbase_t*, const TRI_voc_cid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief looks up a (document) collection by name
////////////////////////////////////////////////////////////////////////////////
@ -518,22 +528,12 @@ TRI_vocbase_col_t* TRI_LookupCollectionByNameVocBase (TRI_vocbase_t*, char const
TRI_vocbase_col_t* TRI_LookupCollectionByIdVocBase (TRI_vocbase_t*, TRI_voc_cid_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief finds a collection by name
/// @brief finds a collection by name or creates it
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_FindCollectionByNameVocBase (TRI_vocbase_t*, char const*, bool bear);
////////////////////////////////////////////////////////////////////////////////
/// @brief finds a primary collection by name
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_FindDocumentCollectionByNameVocBase (TRI_vocbase_t*, char const*, bool bear);
////////////////////////////////////////////////////////////////////////////////
/// @brief finds an edge collection by name
////////////////////////////////////////////////////////////////////////////////
TRI_vocbase_col_t* TRI_FindEdgeCollectionByNameVocBase (TRI_vocbase_t*, char const*, bool bear);
TRI_vocbase_col_t* TRI_FindCollectionByNameOrBearVocBase (TRI_vocbase_t*,
char const*,
const TRI_col_type_t);
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new (document) collection from parameter set

View File

@ -62,12 +62,6 @@ using namespace triagens::httpclient;
using namespace triagens::v8client;
using namespace triagens::arango;
#include "js/common/bootstrap/js-print.h"
#include "js/common/bootstrap/js-modules.h"
#include "js/common/bootstrap/js-monkeypatches.h"
#include "js/common/bootstrap/js-errors.h"
#include "js/client/js-client.h"
// -----------------------------------------------------------------------------
// --SECTION-- private variables
// -----------------------------------------------------------------------------
@ -1341,30 +1335,33 @@ int main (int argc, char* argv[]) {
// load java script from js/bootstrap/*.h files
if (StartupPath.empty()) {
StartupLoader.defineScript("common/bootstrap/modules.js", JS_common_bootstrap_modules);
StartupLoader.defineScript("common/bootstrap/monkeypatches.js", JS_common_bootstrap_monkeypatches);
StartupLoader.defineScript("common/bootstrap/print.js", JS_common_bootstrap_print);
StartupLoader.defineScript("common/bootstrap/errors.js", JS_common_bootstrap_errors);
StartupLoader.defineScript("client/client.js", JS_client_client);
}
else {
LOGGER_DEBUG << "using JavaScript startup files at '" << StartupPath << "'";
StartupLoader.setDirectory(StartupPath);
LOGGER_FATAL << "no 'javascript.startup-directory' has been supplied, giving up";
TRI_FlushLogging();
exit(EXIT_FAILURE);
}
LOGGER_DEBUG << "using JavaScript startup files at '" << StartupPath << "'";
StartupLoader.setDirectory(StartupPath);
context->Global()->Set(v8::String::New("ARANGO_QUIET"), v8::Boolean::New(BaseClient.quiet()), v8::ReadOnly);
context->Global()->Set(v8::String::New("VALGRIND"), v8::Boolean::New((RUNNING_ON_VALGRIND) > 0));
// load all init files
char const* files[] = {
"common/bootstrap/modules.js",
"common/bootstrap/monkeypatches.js",
"common/bootstrap/print.js",
"common/bootstrap/errors.js",
"client/client.js"
};
vector<string> files;
files.push_back("common/bootstrap/modules.js");
files.push_back("common/bootstrap/module-internal.js");
files.push_back("common/bootstrap/module-fs.js");
files.push_back("common/bootstrap/module-console.js");
if (JsLint.empty()) {
files.push_back("common/bootstrap/monkeypatches.js");
}
files.push_back("common/bootstrap/errors.js");
files.push_back("client/client.js");
for (size_t i = 0; i < sizeof(files) / sizeof(files[0]); ++i) {
for (size_t i = 0; i < files.size(); ++i) {
bool ok = StartupLoader.loadScript(context, files[i]);
if (ok) {

View File

@ -1,11 +0,0 @@
#!/bin/bash
NAME=`echo $1 | sed -e 's:^\(.*/\)*js/\(.*\)\.js$:\2:' | tr "/-" "__"`
#cat $1 \
# | sed -e 's:\(["\]\):\\\1:g' \
# | awk 'BEGIN {print "static string JS_'$NAME' = string(\"\") " } { print " + \"" $0 "\\n\"" } END { print ";"}'
cat $1 \
| sed -e 's:\(["\]\):\\\1:g' \
| awk 'BEGIN {print "const char* JS_'$NAME'[] = {" } { print " \"" $0 "\"," } END { print " \"//__end__\"\n};"}'

View File

@ -2,4 +2,5 @@
endpoint = tcp://localhost:8529
[javascript]
startup-directory = @PKGDATADIR@/js
modules-path = @PKGDATADIR@/js/client/modules;@PKGDATADIR@/js/common/modules

View File

@ -1,2 +1,3 @@
[javascript]
startup-directory = ./js
modules-path = ./js/client/modules;./js/common/modules

View File

@ -27,13 +27,14 @@
<script type="text/javascript" src="js/jquery.jeditable.js"></script>
<script type="text/javascript" src="js/jquery.jeditable.autogrow.js"></script>
<script type="text/javascript" src="js/master.js"></script>
<script type="text/javascript" src="js/avocsh1.js"></script>
<script type="text/javascript" src="js/print.js"></script>
<script type="text/javascript" src="js/errors.js"></script>
<script type="text/javascript" src="js/arangodb/browser.js"></script>
<script type="text/javascript" src="js/arangodb/errors.js"></script>
<script type="text/javascript" src="js/arangodb/module-internal.js"></script>
<script type="text/javascript" src="js/arangodb/monkeypatches.js"></script>
<script type="text/javascript" src="js/modules/simple-query-basics.js"></script>
<script type="text/javascript" src="js/modules/simple-query.js"></script>
<script type="text/javascript" src="js/modules/statement-basics.js"></script>
<script type="text/javascript" src="js/client.js"></script>
<script type="text/javascript" src="js/arangodb/client.js"></script>
<style>
a:link {color: #797979; text-decoration: none;}
a:visited {color: #797979; text-decoration: none;}

View File

@ -1,11 +1,5 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*global module, ModuleCache, $ */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global $ */
////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoDB web browser shell
@ -14,7 +8,7 @@
///
/// DISCLAIMER
///
/// Copyright 2012 triagens GmbH, Cologne, Germany
/// Copyright 2012-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.
@ -31,7 +25,8 @@
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Achim Brandt
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
/// @author Dr. Frank Celler
/// @author Copyright 2012-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
@ -57,8 +52,31 @@ function Module (id) {
this.definition = null;
}
var ModuleCache = {};
var module = ModuleCache["/"] = new Module("/");
////////////////////////////////////////////////////////////////////////////////
/// @brief module cache
////////////////////////////////////////////////////////////////////////////////
Module.prototype.ModuleCache = {};
Module.prototype.ModuleCache["/internal"] = new Module("/internal");
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public variables
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief global module
////////////////////////////////////////////////////////////////////////////////
var module = Module.prototype.ModuleCache["/"] = new Module("/");
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -136,6 +154,23 @@ Module.prototype.normalise = function (path) {
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief sets a new module definition
////////////////////////////////////////////////////////////////////////////////
Module.prototype.define = function (path, definition) {
// first get rid of any ".." and "."
path = this.normalise(path);
// check if you already know the module, return the exports
if (! Module.prototype.ModuleCache.hasOwnProperty(path)) {
Module.prototype.ModuleCache[path] = new Module(path);
}
Module.prototype.ModuleCache[path].definition = definition;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief executes a definition or creates a new module descriptor
////////////////////////////////////////////////////////////////////////////////
@ -147,11 +182,11 @@ Module.prototype.require = function (path) {
path = this.normalise(path);
// check if you already know the module, return the exports
if (ModuleCache.hasOwnProperty(path)) {
module = ModuleCache[path];
if (Module.prototype.ModuleCache.hasOwnProperty(path)) {
module = Module.prototype.ModuleCache[path];
}
else {
module = ModuleCache[path] = new Module(path);
module = Module.prototype.ModuleCache[path] = new Module(path);
}
if (module.definition !== null) {
@ -163,21 +198,22 @@ Module.prototype.require = function (path) {
};
////////////////////////////////////////////////////////////////////////////////
/// @brief sets a new module definition
/// @brief global require function
////////////////////////////////////////////////////////////////////////////////
Module.prototype.define = function (path, definition) {
function require (path) {
return module.require(path);
}
// first get rid of any ".." and "."
path = this.normalise(path);
////////////////////////////////////////////////////////////////////////////////
/// @brief global print function
////////////////////////////////////////////////////////////////////////////////
// check if you already know the module, return the exports
if (! ModuleCache.hasOwnProperty(path)) {
ModuleCache[path] = new Module(path);
}
function print () {
var internal = require("internal");
ModuleCache[path].definition = definition;
};
internal.print.apply(internal.print, arguments);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -278,7 +314,6 @@ ArangoConnection.prototype._delete = function (url) {
return msg;
};
ArangoConnection.prototype.DELETE = ArangoConnection.prototype._delete;
////////////////////////////////////////////////////////////////////////////////
@ -416,13 +451,8 @@ var arango = new ArangoConnection();
/// @brief module cache
////////////////////////////////////////////////////////////////////////////////
ModuleCache["/internal"] = new Module("/internal");
(function () {
var internal = ModuleCache["/internal"].exports;
internal.start_pager = function() {};
internal.stop_pager = function() {};
var internal = Module.prototype.ModuleCache["/internal"].exports;
////////////////////////////////////////////////////////////////////////////////
/// @brief global output buffer
@ -430,6 +460,28 @@ ModuleCache["/internal"] = new Module("/internal");
internal.browserOutputBuffer = "";
////////////////////////////////////////////////////////////////////////////////
/// @brief escapes HTML
////////////////////////////////////////////////////////////////////////////////
internal.escapeHTML = (function() {
var MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&#34;',
"'": '&#39;',
"\n": '<br>',
" ": '&nbsp;'
};
var repl = function(c) { return MAP[c]; };
return function(s) {
return s.replace(/[&<>'"\n ]/g, repl); //'
};
}());
////////////////////////////////////////////////////////////////////////////////
/// @brief outputs text to shell window
////////////////////////////////////////////////////////////////////////////////
@ -459,7 +511,7 @@ ModuleCache["/internal"] = new Module("/internal");
text = String(value);
}
internal.browserOutputBuffer += escapeHTML(text);
internal.browserOutputBuffer += internal.escapeHTML(text);
}
};
@ -484,51 +536,9 @@ ModuleCache["/internal"] = new Module("/internal");
}());
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoShell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief escapes HTML
////////////////////////////////////////////////////////////////////////////////
var escapeHTML = (function() {
var MAP = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&#34;',
"'": '&#39;',
"\n": '<br>',
" ": '&nbsp;'
};
var repl = function(c) { return MAP[c]; };
return function(s) {
return s.replace(/[&<>'"\n ]/g, repl); //'
};
}());
////////////////////////////////////////////////////////////////////////////////
/// @brief global require function
////////////////////////////////////////////////////////////////////////////////
function require (path) {
return module.require(path);
}
function ARANGO_QUIET (path) {
return false;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"

View File

@ -0,0 +1 @@
../../../../js/client/client.js

View File

@ -0,0 +1 @@
../../../../js/common/bootstrap/errors.js

View File

@ -0,0 +1 @@
../../../../js/common/bootstrap/module-internal.js

View File

@ -0,0 +1 @@
../../../../js/common/bootstrap/monkeypatches.js

View File

@ -1 +0,0 @@
../../../js/client/client.js

View File

@ -1 +0,0 @@
../../../js/common/bootstrap/errors.js

View File

@ -1190,7 +1190,8 @@ var lastFormatQuestion = true;
command = data;
}
var client = "arangosh> " + escapeHTML(data) + "<br>";
var internal = require("internal");
var client = "arangosh> " + internal.escapeHTML(data) + "<br>";
$('#avocshWindow').append('<b class="avocshClient">' + client + '</b>');
evaloutput(command);

View File

@ -1 +0,0 @@
../../../js/common/bootstrap/print.js

View File

@ -9,10 +9,26 @@
################################################################################
JAVASCRIPT_JSLINT = \
@srcdir@/html/admin/js/arangodb/browser.js \
@srcdir@/js/actions/system/api-collection.js \
@srcdir@/js/actions/system/api-structure.js \
@srcdir@/js/client/modules/org/arangodb.js \
@srcdir@/js/client/modules/org/arangodb/deploy.js \
@srcdir@/js/common/bootstrap/errors.js \
@srcdir@/js/common/bootstrap/module-console.js \
@srcdir@/js/common/bootstrap/module-fs.js \
@srcdir@/js/common/bootstrap/module-internal.js \
@srcdir@/js/common/bootstrap/modules.js \
@srcdir@/js/common/bootstrap/monkeypatches.js \
@srcdir@/js/server/ArangoCollection.js \
@srcdir@/js/server/ArangoStructure.js
@srcdir@/js/server/ArangoStructure.js \
@srcdir@/js/server/modules/org/arangodb.js \
@srcdir@/js/server/modules/org/arangodb/actions.js \
@srcdir@/js/server/modules/org/arangodb/actions/echoController.js \
@srcdir@/js/server/modules/org/arangodb/actions/staticContentController.js \
@srcdir@/js/server/modules/org/arangodb/formatter.js \
@srcdir@/js/server/modules/org/arangodb/parser.js \
@srcdir@/js/server/modules/org/arangodb/validator.js
################################################################################
### @brief executes jslint
@ -39,8 +55,6 @@ BUILT_SOURCES += @builddir@/.setup-js-directories
@builddir@/.setup-js-directories:
@test -d html/admin/js/modules || mkdir -p html/admin/js/modules
@test -d js/common/bootstrap || mkdir -p js/common/bootstrap
@test -d js/client || mkdir -p js/client
@touch $@
################################################################################
@ -53,15 +67,6 @@ html/admin/js/modules/%.js: @srcdir@/js/common/modules/%.js .setup-js-directorie
html/admin/js/modules/%.js: @srcdir@/js/client/modules/%.js .setup-js-directories
(echo "module.define(\"`basename $< .js`\", function(exports, module) {" && cat $< && echo "});") > $@
js/js-%.h: @srcdir@/js/%.js .setup-js-directories
@top_srcdir@/config/js2c.sh $< > $@
js/client/js-%.h: @srcdir@/js/client/%.js .setup-js-directories
@top_srcdir@/config/js2c.sh $< > $@
js/common/bootstrap/js-%.h: @srcdir@/js/common/bootstrap/%.js .setup-js-directories
@top_srcdir@/config/js2c.sh $< > $@
################################################################################
### @brief cleanup
################################################################################

File diff suppressed because it is too large Load Diff

View File

@ -158,7 +158,7 @@ function post_api_collection (req, res) {
}
if (! body.hasOwnProperty("name")) {
actions.resultBad(req, res, actions.ERROR_ARANGO_ILLEGAL_NAME,
actions.resultBad(req, res, arangodb.ERROR_ARANGO_ILLEGAL_NAME,
"name must be non-empty");
return;
}
@ -393,7 +393,7 @@ function get_api_collection (req, res) {
name = decodeURIComponent(req.suffix[0]);
}
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
@ -670,7 +670,7 @@ function put_api_collection_rename (req, res, collection) {
}
if (! body.hasOwnProperty("name")) {
actions.resultBad(req, res, actions.ERROR_ARANGO_ILLEGAL_NAME,
actions.resultBad(req, res, arangodb.ERROR_ARANGO_ILLEGAL_NAME,
"name must be non-empty");
return;
}
@ -701,7 +701,7 @@ function put_api_collection (req, res) {
}
var name = decodeURIComponent(req.suffix[0]);
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
@ -769,7 +769,7 @@ function delete_api_collection (req, res) {
}
else {
var name = decodeURIComponent(req.suffix[0]);
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);

View File

@ -26,21 +26,22 @@
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var actions = require("org/arangodb/actions");
// -----------------------------------------------------------------------------
// --SECTION-- global variables
// -----------------------------------------------------------------------------
var actions = require("org/arangodb/actions");
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoAPI
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief create a cursor and return the first results
///
@ -123,7 +124,7 @@ var actions = require("org/arangodb/actions");
function POST_api_cursor(req, res) {
if (req.suffix.length != 0) {
actions.resultNotFound(req, res, internal.errors.ERROR_CURSOR_NOT_FOUND.code, internal.errors.ERROR_CURSOR_NOT_FOUND.message);
actions.resultNotFound(req, res, arangodb.ERROR_CURSOR_NOT_FOUND);
return;
}
@ -143,7 +144,7 @@ function POST_api_cursor(req, res) {
(json.batchSize == undefined));
}
else {
actions.resultBad(req, res, actions.ERROR_QUERY_EMPTY);
actions.resultBad(req, res, arangodb.ERROR_QUERY_EMPTY);
return;
}
@ -196,9 +197,9 @@ function POST_api_cursor(req, res) {
/// @verbinclude api-cursor-invalid-cursor-identifier
////////////////////////////////////////////////////////////////////////////////
function PUT_api_cursor(req, res) {
function PUT_api_cursor (req, res) {
if (req.suffix.length != 1) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER);
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
return;
}
@ -206,7 +207,7 @@ function PUT_api_cursor(req, res) {
var cursor = CURSOR(cursorId);
if (! (cursor instanceof ArangoCursor)) {
actions.resultBad(req, res, actions.ERROR_CURSOR_NOT_FOUND);
actions.resultBad(req, res, arangodb.ERROR_CURSOR_NOT_FOUND);
return;
}
@ -253,13 +254,13 @@ function PUT_api_cursor(req, res) {
function DELETE_api_cursor(req, res) {
if (req.suffix.length != 1) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER);
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER);
return;
}
var cursorId = decodeURIComponent(req.suffix[0]);
if (! DELETE_CURSOR(cursorId)) {
actions.resultNotFound(req, res, internal.errors.ERROR_CURSOR_NOT_FOUND.code, internal.errors.ERROR_CURSOR_NOT_FOUND.message);
actions.resultNotFound(req, res, arangodb.ERROR_CURSOR_NOT_FOUND);
return;
}

View File

@ -25,8 +25,9 @@
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var actions = require("org/arangodb/actions");
var internal = require("internal");
var API = "/_api/edges";
////////////////////////////////////////////////////////////////////////////////
@ -71,14 +72,14 @@ var API = "/_api/edges";
function GET_edges (req, res) {
if (req.suffix.length !== 1) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expect GET /" + API + "/<collection-identifer>?vertex=<vertex-handle>&direction=<direction>");
return;
}
var name = decodeURIComponent(req.suffix[0]);
var id = parseInt(name) || name;
var collection = internal.db._collection(id);
var collection = arangodb.db._collection(id);
if (collection === null) {
actions.collectionNotFound(req, res, name);
@ -99,7 +100,7 @@ function GET_edges (req, res) {
e = collection.outEdges(vertex);
}
else {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"<direction> must be any, in, or out, not: " + JSON.stringify(direction));
return;
}

View File

@ -25,7 +25,9 @@
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var actions = require("org/arangodb/actions");
var API = "_api/index";
// -----------------------------------------------------------------------------
@ -71,7 +73,7 @@ var API = "_api/index";
function GET_api_indexes (req, res) {
var name = req.parameters.collection;
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
@ -131,7 +133,7 @@ function GET_api_index (req, res) {
else if (req.suffix.length === 2) {
var name = decodeURIComponent(req.suffix[0]);
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
@ -149,7 +151,7 @@ function GET_api_index (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, index);
}
else {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expect GET /" + API + "/<index-handle>");
}
}
@ -183,7 +185,7 @@ function GET_api_index (req, res) {
function POST_api_index_cap (req, res, collection, body) {
if (! body.hasOwnProperty("size")) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expecting a size");
}
@ -260,7 +262,7 @@ function POST_api_index_geo (req, res, collection, body) {
var fields = body.fields;
if (! (fields instanceof Array)) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"fields must be a list of attribute paths: " + fields);
}
@ -316,7 +318,7 @@ function POST_api_index_geo (req, res, collection, body) {
// something is wrong
else {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"fields must be a list of attribute paths of length 1 or 2: " + fields);
return;
}
@ -371,7 +373,7 @@ function POST_api_index_hash (req, res, collection, body) {
var fields = body.fields;
if (! (fields instanceof Array)) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"fields must be a list of attribute paths: " + fields);
}
@ -430,7 +432,7 @@ function POST_api_index_skiplist (req, res, collection, body) {
var fields = body.fields;
if (! (fields instanceof Array)) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"fields must be a list of attribute paths: " + fields);
}
@ -544,7 +546,7 @@ function POST_api_index_bitarray (req, res, collection, body) {
var fields = body.fields;
if (! (fields instanceof Array)) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"fields must be a list of attribute paths: " + fields);
}
@ -618,7 +620,7 @@ function POST_api_index (req, res) {
}
var name = req.parameters.collection;
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
@ -650,7 +652,7 @@ function POST_api_index (req, res) {
POST_api_index_bitarray(req, res, collection, body);
}
else {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"unknown index type '" + body.type + "'");
}
}
@ -671,13 +673,13 @@ function POST_api_index (req, res) {
function DELETE_api_index (req, res) {
if (req.suffix.length !== 2) {
actions.resultBad(req, res, actions.ERROR_HTTP_BAD_PARAMETER,
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expect DELETE /" + API + "/<index-handle>");
return;
}
var name = decodeURIComponent(req.suffix[0]);
var collection = internal.db._collection(name);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);

View File

@ -5,7 +5,7 @@
vars: true,
white: true,
plusplus: true */
/*global require, exports */
/*global require, exports, module */
////////////////////////////////////////////////////////////////////////////////
/// @brief administration actions
@ -34,10 +34,9 @@
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function() {
var actions = require("org/arangodb/actions");
var internal = require("internal");
var console = require("internal");
var actions = require("org/arangodb/actions");
var internal = require("internal");
var console = require("console");
// -----------------------------------------------------------------------------
// --SECTION-- standard routing
@ -52,75 +51,75 @@
/// @brief routing function
////////////////////////////////////////////////////////////////////////////////
function Routing (req, res) {
var action;
var execute;
var next;
var path = req.suffix.join("/");
function Routing (req, res) {
var action;
var execute;
var next;
var path = req.suffix.join("/");
action = actions.firstRouting(req.requestType, req.suffix);
action = actions.firstRouting(req.requestType, req.suffix);
execute = function () {
if (action.route === undefined) {
actions.resultNotImplemented(req, res, "unknown path '" + path + "'");
return;
}
execute = function () {
if (action.route === undefined) {
actions.resultNotImplemented(req, res, "unknown path '" + path + "'");
return;
}
if (action.route.path !== undefined) {
req.path = action.route.path;
}
else {
delete req.path;
}
if (action.route.path !== undefined) {
req.path = action.route.path;
}
else {
delete req.path;
}
if (action.prefix !== undefined) {
req.prefix = action.prefix;
}
else {
delete req.prefix;
}
if (action.prefix !== undefined) {
req.prefix = action.prefix;
}
else {
delete req.prefix;
}
if (action.suffix !== undefined) {
req.suffix = action.suffix;
}
else {
delete req.suffix;
}
if (action.suffix !== undefined) {
req.suffix = action.suffix;
}
else {
delete req.suffix;
}
if (action.urlParameters !== undefined) {
req.urlParameters = action.urlParameters;
}
else {
req.urlParameters = {};
}
if (action.urlParameters !== undefined) {
req.urlParameters = action.urlParameters;
}
else {
req.urlParameters = {};
}
var func = action.route.callback.controller;
if (func === null || typeof func !== 'function') {
func = actions.errorFunction(action.route, 'Invalid callback definition found for route ' + JSON.stringify(action.route));
}
var func = action.route.callback.controller;
if (func === null || typeof func !== 'function') {
func = actions.errorFunction(action.route, 'Invalid callback definition found for route ' + JSON.stringify(action.route));
}
try {
func(req, res, action.route.callback.options, next);
}
catch (err) {
actions.errorFunction(action.route, 'A runtime error occurred while executing an action: ' + String(err))(req, res, action.route.callback.options, next);
}
};
next = function () {
action = actions.nextRouting(action);
execute();
};
try {
func(req, res, action.route.callback.options, next);
}
catch (err) {
actions.errorFunction(action.route, 'A runtime error occurred while executing an action: ' + String(err))(req, res, action.route.callback.options, next);
}
};
next = function () {
action = actions.nextRouting(action);
execute();
}
};
actions.defineHttp({
url : "",
prefix : true,
context : "admin",
callback : Routing
});
execute();
}
actions.defineHttp({
url : "",
prefix : true,
context : "admin",
callback : Routing
});
////////////////////////////////////////////////////////////////////////////////
/// @brief reloads the server authentication information
@ -140,28 +139,29 @@
/// @brief reloads the routing information
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/routing/reload",
context : "admin",
prefix : false,
callback : function (req, res) {
internal.executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()");
actions.resultOk(req, res, actions.HTTP_OK);
}
});
actions.defineHttp({
url : "_admin/routing/reload",
context : "admin",
prefix : false,
callback : function (req, res) {
internal.executeGlobalContextFunction("require(\"org/arangodb/actions\").reloadRouting()");
console.warn("about to flush the routing cache");
actions.resultOk(req, res, actions.HTTP_OK);
}
});
////////////////////////////////////////////////////////////////////////////////
/// @brief returns the current routing information
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/routing/routes",
context : "admin",
prefix : false,
callback : function (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, actions.routingCache());
}
});
actions.defineHttp({
url : "_admin/routing/routes",
context : "admin",
prefix : false,
callback : function (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, actions.routingCache());
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -176,6 +176,21 @@
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief flushes the modules cache
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/modules/flush",
context : "admin",
prefix : false,
callback : function (req, res) {
internal.executeGlobalContextFunction("require(\"internal\").flushModuleCache()");
console.warn("about to flush the modules cache");
actions.resultOk(req, res, actions.HTTP_OK);
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_GET_admin_time
/// @brief returns the system time
@ -188,14 +203,14 @@
/// current system time as a Unix timestamp with microsecond precision.
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/time",
context : "admin",
prefix : false,
callback : function (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, { time : internal.time() });
}
});
actions.defineHttp({
url : "_admin/time",
context : "admin",
prefix : false,
callback : function (req, res) {
actions.resultOk(req, res, actions.HTTP_OK, { time : internal.time() });
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_GET_admin_echo
@ -214,16 +229,16 @@
/// - @LIT{parameters}: list of URL parameters received
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/echo",
context : "admin",
prefix : true,
callback : function (req, res) {
res.responseCode = actions.HTTP_OK;
res.contentType = "application/json; charset=utf-8";
res.body = JSON.stringify(req);
}
});
actions.defineHttp({
url : "_admin/echo",
context : "admin",
prefix : true,
callback : function (req, res) {
res.responseCode = actions.HTTP_OK;
res.contentType = "application/json; charset=utf-8";
res.body = JSON.stringify(req);
}
});
////////////////////////////////////////////////////////////////////////////////
/// @fn JSF_GET_admin_status
@ -260,24 +275,24 @@
/// made which have required loading a memory page from disk.
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/status",
context : "admin",
actions.defineHttp({
url : "_admin/status",
context : "admin",
callback : function (req, res) {
var result;
callback : function (req, res) {
var result;
try {
result = {};
result.system = SYS_PROCESS_STAT();
try {
result = {};
result.system = internal.processStat();
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err);
}
actions.resultOk(req, res, actions.HTTP_OK, result);
}
});
catch (err) {
actions.resultException(req, res, err);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
@ -292,83 +307,81 @@
/// @{
////////////////////////////////////////////////////////////////////////////////
function GET_admin_session (req, res) {
var result;
var realm;
function GET_admin_session (req, res) {
var result;
var realm;
if (req.user === null) {
realm = "basic realm=\"arangodb\"";
if (req.user === null) {
realm = "basic realm=\"arangodb\"";
res.responseCode = actions.HTTP_UNAUTHORIZED;
res.headers = { "www-authenticate" : realm };
}
else {
var user = internal.db._collection("_users").firstExample({ user : req.user });
res.responseCode = actions.HTTP_UNAUTHORIZED;
res.headers = { "www-authenticate" : realm };
}
else {
var user = internal.db._collection("_users").firstExample({ user : req.user });
if (user === null) {
actions.resultNotFound(req, res, internal.errors.ERROR_HTTP_NOT_FOUND.code, "unknown user '" + req.user + "'");
}
else {
result = {
user : user.user,
permissions : user.permissions || []
};
actions.resultOk(req, res, actions.HTTP_OK, result);
}
}
if (user === null) {
actions.resultNotFound(req, res, internal.errors.ERROR_HTTP_NOT_FOUND.code, "unknown user '" + req.user + "'");
}
else {
result = {
user : user.user,
permissions : user.permissions || []
};
function POST_admin_session (req, res) {
actions.resultUnsupported(req, res);
actions.resultOk(req, res, actions.HTTP_OK, result);
}
}
}
function PUT_admin_session (req, res) {
actions.resultUnsupported(req, res);
}
function POST_admin_session (req, res) {
actions.resultUnsupported(req, res);
}
function DELETE_admin_session (req, res) {
actions.resultUnsupported(req, res);
}
function PUT_admin_session (req, res) {
actions.resultUnsupported(req, res);
}
function DELETE_admin_session (req, res) {
actions.resultUnsupported(req, res);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief session call dispatcher
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_admin/session",
context : "admin",
prefix : false,
callback : function (req, res) {
try {
if (req.requestType === actions.GET) {
GET_admin_session(req, res);
}
else if (req.requestType === actions.DELETE) {
DELETE_admin_session(req, res);
}
else if (req.requestType === actions.POST) {
POST_admin_session(req, res);
}
else if (req.requestType === actions.PUT) {
PUT_admin_session(req, res);
}
else {
actions.resultUnsupported(req, res);
}
actions.defineHttp({
url : "_admin/session",
context : "admin",
prefix : false,
callback : function (req, res) {
try {
if (req.requestType === actions.GET) {
GET_admin_session(req, res);
}
catch (err) {
actions.resultException(req, res, err);
else if (req.requestType === actions.DELETE) {
DELETE_admin_session(req, res);
}
else if (req.requestType === actions.POST) {
POST_admin_session(req, res);
}
else if (req.requestType === actions.PUT) {
PUT_admin_session(req, res);
}
else {
actions.resultUnsupported(req, res);
}
}
});
catch (err) {
actions.resultException(req, res, err);
}
}
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
})();
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
@ -377,4 +390,3 @@
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:

View File

@ -118,7 +118,7 @@ function buildDocumentFromReq(req) {
function postKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.resultBad(req, res, actions.ERROR_KEYVALUE_INVALID_KEY, actions.getErrorMessage(actions.ERROR_KEYVALUE_INVALID_KEY));
actions.resultBad(req, res, arangodb.ERROR_KEYVALUE_INVALID_KEY);
return;
}
@ -130,7 +130,7 @@ function postKeyValue(req, res) {
}
if (req.requestBody == "") {
actions.resultError(req, res, actions.HTTP_BAD, actions.ERROR_KEYVALUE_NO_VALUE, actions.getErrorMessage(actions.ERROR_KEYVALUE_NO_VALUE));
actions.resultError(req, res, actions.HTTP_BAD, arangodb.ERROR_KEYVALUE_NO_VALUE, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_NO_VALUE));
return;
}
@ -139,7 +139,7 @@ function postKeyValue(req, res) {
var oldDoc = internal.db._collection(collection).firstExample("$key", doc["$key"]);
if (oldDoc != undefined) {
actions.resultError(req, res, actions.HTTP_BAD, actions.ERROR_KEYVALUE_KEY_EXISTS, actions.getErrorMessage(actions.ERROR_KEYVALUE_KEY_EXISTS));
actions.resultError(req, res, actions.HTTP_BAD, arangodb.ERROR_KEYVALUE_KEY_EXISTS, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_KEY_EXISTS));
}
else {
var id = db[collection].save(doc);
@ -161,7 +161,7 @@ function postKeyValue(req, res) {
function putKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.resultBad(req, res, actions.ERROR_KEYVALUE_INVALID_KEY, actions.getErrorMessage(actions.ERROR_KEYVALUE_INVALID_KEY));
actions.resultBad(req, res, arangodb.ERROR_KEYVALUE_INVALID_KEY);
return;
}
@ -186,7 +186,7 @@ function putKeyValue(req, res) {
actions.resultOk(req, res, actions.HTTP_CREATED, result);
return;
}
actions.resultError(req, res, actions.HTTP_NOT_FOUND, actions.ERROR_KEYVALUE_KEY_NOT_FOUND, actions.getErrorMessage(actions.ERROR_KEYVALUE_KEY_NOT_FOUND));
actions.resultError(req, res, actions.HTTP_NOT_FOUND, arangodb.ERROR_KEYVALUE_KEY_NOT_FOUND, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_KEY_NOT_FOUND));
}
else {
// get _id
@ -203,7 +203,7 @@ function putKeyValue(req, res) {
actions.resultOk(req, res, actions.HTTP_ACCEPTED, {"changed" : true});
}
else {
actions.resultError(req, res, actions.HTTP_BAD, actions.ERROR_KEYVALUE_KEY_NOT_CHANGED, actions.getErrorMessage(actions.ERROR_KEYVALUE_KEY_NOT_CHANGED));
actions.resultError(req, res, actions.HTTP_BAD, arangodb.ERROR_KEYVALUE_KEY_NOT_CHANGED, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_KEY_NOT_CHANGED));
}
}
}
@ -217,7 +217,7 @@ function putKeyValue(req, res) {
function deleteKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.resultBad(req, res, actions.ERROR_KEYVALUE_INVALID_KEY, actions.getErrorMessage(actions.ERROR_KEYVALUE_INVALID_KEY));
actions.resultBad(req, res, arangodb.ERROR_KEYVALUE_INVALID_KEY);
return;
}
@ -237,7 +237,7 @@ function deleteKeyValue(req, res) {
var doc = internal.db._collection(collection).firstExample("$key", key);
if (doc == undefined) {
actions.resultError(req, res, actions.HTTP_NOT_FOUND, actions.ERROR_KEYVALUE_KEY_NOT_FOUND, actions.getErrorMessage(actions.ERROR_KEYVALUE_KEY_NOT_FOUND));
actions.resultError(req, res, actions.HTTP_NOT_FOUND, arangodb.ERROR_KEYVALUE_KEY_NOT_FOUND, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_KEY_NOT_FOUND));
}
else {
var id = doc._id;
@ -245,7 +245,7 @@ function deleteKeyValue(req, res) {
actions.resultOk(req, res, actions.HTTP_ACCEPTED, {"removed" : true});
}
else {
actions.resultError(req, res, actions.HTTP_BAD, actions.ERROR_KEYVALUE_KEY_NOT_REMOVED, actions.getErrorMessage(actions.ERROR_KEYVALUE_KEY_NOT_REMOVED));
actions.resultError(req, res, actions.HTTP_BAD, arangodb.ERROR_KEYVALUE_KEY_NOT_REMOVED, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_KEY_NOT_REMOVED));
}
}
}
@ -261,7 +261,7 @@ function deleteKeyValue(req, res) {
function getKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.resultBad(req, res, actions.ERROR_KEYVALUE_INVALID_KEY, actions.getErrorMessage(actions.ERROR_KEYVALUE_INVALID_KEY));
actions.resultBad(req, res, arangodb.ERROR_KEYVALUE_INVALID_KEY);
return;
}
@ -281,7 +281,7 @@ function getKeyValue(req, res) {
var doc = internal.db._collection(collection).firstExample("$key", key);
if (doc == undefined) {
actions.resultError(req, res, actions.HTTP_NOT_FOUND, actions.ERROR_KEYVALUE_KEY_NOT_FOUND, actions.getErrorMessage(actions.ERROR_KEYVALUE_KEY_NOT_FOUND));
actions.resultError(req, res, actions.HTTP_NOT_FOUND, arangodb.ERROR_KEYVALUE_KEY_NOT_FOUND, actions.getErrorMessage(arangodb.ERROR_KEYVALUE_KEY_NOT_FOUND));
}
else {
var headers = {};
@ -367,7 +367,7 @@ actions.defineHttp({
function searchKeyValue(req, res) {
if (req.suffix.length < 2) {
actions.resultBad(req, res, actions.ERROR_KEYVALUE_INVALID_KEY, actions.getErrorMessage(actions.ERROR_KEYVALUE_INVALID_KEY));
actions.resultBad(req, res, arangodb.ERROR_KEYVALUE_INVALID_KEY);
return;
}

View File

@ -76,6 +76,8 @@ function ArangoError (error) {
(function () {
var internal = require("internal");
internal.ArangoError = ArangoError;
////////////////////////////////////////////////////////////////////////////////
/// @brief prints an error
////////////////////////////////////////////////////////////////////////////////
@ -386,12 +388,6 @@ function help () {
(function () {
var internal = require("internal");
////////////////////////////////////////////////////////////////////////////////
/// @brief be quiet
////////////////////////////////////////////////////////////////////////////////
internal.ARANGO_QUIET = ARANGO_QUIET;
////////////////////////////////////////////////////////////////////////////////
/// @brief log function
////////////////////////////////////////////////////////////////////////////////
@ -400,6 +396,16 @@ function help () {
internal.output(level, ": ", msg, "\n");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief flushes the module cache of the server
////////////////////////////////////////////////////////////////////////////////
internal.flushServerModules = function () {
if (typeof arango !== 'undefined') {
arango.POST("/_admin/modules/flush", "");
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief rebuilds the routing cache
////////////////////////////////////////////////////////////////////////////////
@ -1703,7 +1709,7 @@ function ArangoCollection (database, data) {
};
////////////////////////////////////////////////////////////////////////////////
/// @brief delete a document in the collection, identified by its id
/// @brief removes a document in the collection, identified by its id
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.remove = function (id, overwrite) {
@ -1748,7 +1754,26 @@ function ArangoCollection (database, data) {
};
////////////////////////////////////////////////////////////////////////////////
/// @brief replace a document in the collection, identified by its id
/// @brief removes documents in the collection, identified by an example
////////////////////////////////////////////////////////////////////////////////
// TODO this is not optiomal, there should a HTTP call handling everything on
// the server
ArangoCollection.prototype.removeByExample = function (example, waitForSync) {
var documents;
documents = this.byExample(example);
while (documents.hasNext()) {
var document = documents.next();
this.remove(document, true, waitForSync);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief replaces a document in the collection, identified by its id
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.replace = function (id, data, overwrite) {

View File

@ -1,10 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
@ -46,6 +40,19 @@ var internal = require("internal");
////////////////////////////////////////////////////////////////////////////////
exports.db = internal.db;
exports.ArangoCollection = internal.ArangoCollection;
exports.ArangoError = internal.ArangoError;
// copy error codes
(function () {
var name;
for (name in internal.errors) {
if (internal.errors.hasOwnProperty(name)) {
exports[name] = internal.errors[name].code;
}
}
}());
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -0,0 +1,512 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, regexp: true, continue: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
/// @brief deployment tools
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 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 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var fs = require("fs");
var internal = require("internal");
// -----------------------------------------------------------------------------
// --SECTION-- ArangoApp
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDeployment
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief application
////////////////////////////////////////////////////////////////////////////////
function ArangoApp (routing, description) {
this._name = description.application;
this._routing = routing;
this._description = description;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDeployment
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief guesses the content type
////////////////////////////////////////////////////////////////////////////////
function guessContentType (filename, content) {
var re = /.*\.([^\.]*)$/;
var match = re.exec(filename);
var extension;
if (match === null) {
return "text/plain; charset=utf-8";
}
extension = match[1];
if (extension === "html") {
return "text/html; charset=utf-8";
}
if (extension === "xml") {
return "application/xml; charset=utf-8";
}
if (extension === "json") {
return "application/json; charset=utf-8";
}
if (extension === "js") {
return "application/x-javascript; charset=utf-8";
}
return "text/plain; charset=utf-8";
}
////////////////////////////////////////////////////////////////////////////////
/// @brief normalizes a path
////////////////////////////////////////////////////////////////////////////////
function normalizePath (url) {
if (url === "") {
url = "/";
}
else if (url[0] !== '/') {
url = "/" + url;
}
return url;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief updates a routing entry
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.updateRoute = function (route) {
var routes;
var i;
routes = this._description.routes;
for (i = 0; i < routes.length; ++i) {
if (routes[i].type === route.type && routes[i].key === route.key) {
routes[i] = route;
return;
}
}
routes.push(route);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints an application
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype._PRINT = function (route) {
internal.output('[ArangoApp "', this._name, '" at "', this._description.urlPrefix, '"]');
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoDeployment
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief mounts one page directly
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.mountStaticContent = function (url, content, contentType) {
var pages;
var name;
if (url === "") {
url = "/";
}
else if (url[0] !== '/') {
url = "/" + url;
}
if (typeof content !== "string") {
content = JSON.stringify(content);
if (contentType === undefined) {
contentType = "application/json; charset=utf-8";
}
}
if (contentType === undefined) {
contentType = "text/html; charset=utf-8";
}
pages = {
type: "StaticContent",
key: url,
url: { match: url },
content: {
contentType: contentType,
body: content,
methods: [ "GET", "HEAD" ]
}
};
this.updateRoute(pages);
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief mounts a bunch of static pages
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.mountStaticPages = function (url, collection) {
var pages;
var name;
if (typeof collection !== "string") {
name = collection.name();
}
else {
name = collection;
}
url = normalizePath(url);
pages = {
type: "StaticPages",
key: url,
url: { match: url + "/*" },
action: {
controller: "org/arangodb/actions/staticContentController",
methods: [ "GET", "HEAD" ],
options: {
contentCollection: name,
prefix: url,
application: this._name
}
}
};
this.updateRoute(pages);
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief mounts a simple action
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.mountAction = function (url, func, methods) {
var pages;
var name;
url = normalizePath(url);
if (methods === undefined) {
methods = [ "GET", "HEAD" ];
}
if (! (methods instanceof Array)) {
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_BAD_PARAMETER;
error.errorMessage = "methods must be a list of HTTP methods, i. e. [\"GET\"]";
throw error;
}
pages = {
type: "Action",
key: url,
url: { match: url },
action: {
'do': func,
methods: methods,
options: {
path: url,
application: this._name
}
}
};
this.updateRoute(pages);
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief changes the common prefix
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.setPrefix = function (prefix) {
if (prefix !== "" && prefix[prefix.length - 1] === '/') {
prefix = prefix.slice(0, prefix.length - 1);
}
if (prefix !== "" && prefix[0] !== '/') {
prefix = "/" + prefix;
}
if (prefix === "/") {
prefix = "";
}
this._description.urlPrefix = prefix;
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief gets the common prefix
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.prefix = function () {
return this._description.urlPrefix;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief saves and reloads
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.save = function () {
var doc;
doc = this._routing.replace(this._description, this._description);
this._description = this._routing.document(doc);
internal.reloadRouting();
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief uploads content from filesystem
////////////////////////////////////////////////////////////////////////////////
ArangoApp.prototype.uploadStaticPages = function (prefix, path) {
var doc;
var files;
var i;
var route;
var routes;
var collection;
var error;
var name;
var re = /.*\/([^\/]*)$/;
routes = this._description.routes;
prefix = normalizePath(prefix);
for (i = 0; i < routes.length; ++i) {
route = routes[i];
if (route.type === "StaticPages" && route.key === prefix) {
break;
}
}
if (routes.length <= i) {
error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_HTTP_NOT_FOUND;
error.errorMessage = "cannot find path '" + prefix + "' in routing table";
throw error;
}
files = fs.listTree(path);
name = route.action.options.contentCollection;
collection = arangodb.db._collection(name);
if (collection === null) {
arangodb.db._createDocumentCollection(name);
collection = arangodb.db._collection(name);
}
collection.ensureHashIndex("application", "prefix", "path");
collection.removeByExample({ application: this._name, prefix: prefix });
for (i = 0; i < files.length; ++i) {
var content;
var contentType;
var file = path + "/" + files[i];
var subpath = "/" + files[i];
var filename;
if (fs.isDirectory(file)) {
continue;
}
content = internal.read(file);
if (content === null) {
continue;
}
filename = re.exec(files[i]);
if (filename !== null) {
filename = filename[1];
}
else {
filename = files[i];
}
contentType = guessContentType(file, content);
collection.save({
application: this._name,
prefix: prefix,
path: subpath,
content: content,
contentType: contentType,
filename: filename
});
internal.print("imported '" + subpath + "' of type '" + contentType + "'");
}
return this;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief creates a new app
////////////////////////////////////////////////////////////////////////////////
exports.createApp = function (name) {
var routing = arangodb.db._collection("_routing");
var doc = routing.firstExample({ application: name });
if (doc !== null) {
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_DUPLICATE_IDENTIFIER;
error.errorMessage = "application name must be unique";
throw error;
}
doc = routing.save({ application: name,
urlPrefix: "",
routes: [],
middleware: [] });
return new ArangoApp(routing, routing.document(doc));
};
////////////////////////////////////////////////////////////////////////////////
/// @brief loads an existing app
////////////////////////////////////////////////////////////////////////////////
exports.readApp = function (name) {
var routing = arangodb.db._collection("_routing");
var doc = routing.firstExample({ application: name });
if (doc === null) {
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_DOCUMENT_NOT_FOUND;
error.errorMessage = "application unknown";
throw error;
}
return new ArangoApp(routing, doc);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief loads a module directory into the database
////////////////////////////////////////////////////////////////////////////////
exports.uploadModules = function (prefix, path) {
var i;
var files;
var re = /^(.*)\.js$/;
prefix = normalizePath(prefix);
files = fs.listTree(path);
for (i = 0; i < files.length; ++i) {
var content;
var mpath;
var file = path + "/" + files[i];
if (fs.isDirectory(file)) {
continue;
}
mpath = re.exec(files[i]);
if (mpath === null) {
internal.print("skipping file '" + files[i] + "' of unknown type, expecting .js");
continue;
}
mpath = prefix + "/" + mpath[1];
internal.defineModule(mpath, file);
internal.print("imported '" + mpath + "'");
}
internal.flushServerModules();
internal.wait(1);
internal.reloadRouting();
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:

View File

@ -0,0 +1,180 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global Module */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "console"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-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
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Module "console"
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleConsole
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief console module
////////////////////////////////////////////////////////////////////////////////
(function () {
var internal = Module.prototype.ModuleCache["/internal"].exports;
var console = Module.prototype.ModuleCache["/console"].exports;
console.getline = internal.getline;
////////////////////////////////////////////////////////////////////////////////
/// @brief logs debug message
///
/// @FUN{console.debug(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// debug message.
///
/// String substitution patterns, which can be used in @FA{format}.
///
/// - @LIT{\%s} string
/// - @LIT{\%d}, @LIT{\%i} integer
/// - @LIT{\%f} floating point number
/// - @LIT{\%o} object hyperlink
////////////////////////////////////////////////////////////////////////////////
console.debug = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("debug", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs error message
///
/// @FUN{console.error(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// error message.
////////////////////////////////////////////////////////////////////////////////
console.error = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("error", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs info message
///
/// @FUN{console.info(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// info message.
////////////////////////////////////////////////////////////////////////////////
console.info = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("info", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs log message
///
/// @FUN{console.log(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// log message.
////////////////////////////////////////////////////////////////////////////////
console.log = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("info", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs warn message
///
/// @FUN{console.warn(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// warn message.
////////////////////////////////////////////////////////////////////////////////
console.warn = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("warning", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
}());
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -0,0 +1,66 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global Module */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "js"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-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
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Module "fs"
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleFS
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief file-system module
////////////////////////////////////////////////////////////////////////////////
(function () {
var internal = Module.prototype.ModuleCache["/internal"].exports;
var fs = Module.prototype.ModuleCache["/fs"].exports;
fs.exists = internal.exists;
fs.isDirectory = internal.isDirectory;
fs.listTree = internal.listTree;
fs.move = internal.move;
fs.remove = internal.remove;
}());
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -0,0 +1,727 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true, proto: true */
/*global require, module, Module, FS_MOVE, FS_REMOVE, FS_EXISTS, FS_IS_DIRECTORY, FS_LIST_TREE,
SYS_EXECUTE, SYS_LOAD, SYS_LOG, SYS_LOG_LEVEL, SYS_OUTPUT, SYS_PROCESS_STAT, SYS_READ,
SYS_SPRINTF, SYS_TIME, SYS_START_PAGER, SYS_STOP_PAGER, SYS_SHA256, SYS_WAIT, SYS_GETLINE,
SYS_PARSE, ARANGO_QUIET, MODULES_PATH, COLOR_OUTPUT, COLOR_OUTPUT_RESET, COLOR_BRIGHT,
COLOR_BLACK, COLOR_BOLD_BLACK, COLOR_BLINK, COLOR_BLUE, COLOR_BOLD_BLUE, COLOR_BOLD_GREEN,
COLOR_RED, COLOR_BOLD_RED, COLOR_GREEN, COLOR_WHITE, COLOR_BOLD_WHITE, COLOR_YELLOW,
COLOR_BOLD_YELLOW, PRETTY_PRINT */
////////////////////////////////////////////////////////////////////////////////
/// @brief module "internal"
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-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
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Module "internal"
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleInternal
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief internal module
////////////////////////////////////////////////////////////////////////////////
(function () {
var internal = Module.prototype.ModuleCache["/internal"].exports;
// system functions
if (typeof SYS_EXECUTE !== "undefined") {
internal.execute = SYS_EXECUTE;
delete SYS_EXECUTE;
}
if (typeof SYS_GETLINE !== "undefined") {
internal.getline = SYS_GETLINE;
delete SYS_GETLINE;
}
if (typeof SYS_LOAD !== "undefined") {
internal.load = SYS_LOAD;
delete SYS_LOAD;
}
if (typeof SYS_LOG !== "undefined") {
internal.log = SYS_LOG;
delete SYS_LOG;
}
if (typeof SYS_LOG_LEVEL !== "undefined") {
internal.logLevel = SYS_LOG_LEVEL;
delete SYS_LOG_LEVEL;
}
if (typeof SYS_OUTPUT !== "undefined") {
internal.output = SYS_OUTPUT;
delete SYS_OUTPUT;
}
if (typeof SYS_PARSE !== "undefined") {
internal.parse= SYS_PARSE;
delete SYS_PARSE;
}
if (typeof SYS_PROCESS_STAT !== "undefined") {
internal.processStat = SYS_PROCESS_STAT;
delete SYS_PROCESS_STAT;
}
if (typeof SYS_READ !== "undefined") {
internal.read = SYS_READ;
delete SYS_READ;
}
if (typeof SYS_SHA256 !== "undefined") {
internal.sha256 = SYS_SHA256;
delete SYS_SHA256;
}
if (typeof SYS_SPRINTF !== "undefined") {
internal.sprintf = SYS_SPRINTF;
delete SYS_SPRINTF;
}
if (typeof SYS_TIME !== "undefined") {
internal.time = SYS_TIME;
delete SYS_TIME;
}
if (typeof SYS_WAIT !== "undefined") {
internal.wait = SYS_WAIT;
delete SYS_WAIT;
}
if (typeof FS_EXISTS !== "undefined") {
internal.exists = FS_EXISTS;
delete FS_EXISTS;
}
if (typeof FS_IS_DIRECTORY !== "undefined") {
internal.isDirectory = FS_IS_DIRECTORY;
delete FS_IS_DIRECTORY;
}
if (typeof FS_LIST_TREE !== "undefined") {
internal.listTree = FS_LIST_TREE;
delete FS_LIST_TREE;
}
if (typeof FS_MOVE !== "undefined") {
internal.move = FS_MOVE;
delete FS_MOVE;
}
if (typeof FS_REMOVE !== "undefined") {
internal.remove = FS_REMOVE;
delete FS_REMOVE;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public constants
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleInternal
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief modules path
////////////////////////////////////////////////////////////////////////////////
internal.MODULES_PATH = "";
if (typeof MODULES_PATH !== "undefined") {
internal.MODULES_PATH = MODULES_PATH;
delete MODULES_PATH;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief quiet flag
////////////////////////////////////////////////////////////////////////////////
internal.ARANGO_QUIET = false;
////////////////////////////////////////////////////////////////////////////////
/// @brief pretty print flag
////////////////////////////////////////////////////////////////////////////////
internal.PRETTY_PRINT = false;
if (typeof PRETTY_PRINT !== "undefined") {
internal.PRETTY_PRINT = PRETTY_PRINT;
delete PRETTY_PRINT;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief color constants
////////////////////////////////////////////////////////////////////////////////
internal.COLOR_OUTPUT = false;
internal.COLOR_OUTPUT_DEFAULT = "";
internal.COLOR_OUTPUT_RESET = "";
internal.COLOR_BRIGHT = "";
if (typeof COLOR_OUTPUT !== "undefined") {
internal.COLOR_OUTPUT = COLOR_OUTPUT;
delete COLOR_OUTPUT;
}
if (typeof COLOR_OUTPUT_RESET !== "undefined") {
internal.COLOR_OUTPUT_RESET = COLOR_OUTPUT_RESET;
delete COLOR_OUTPUT_RESET;
}
if (typeof COLOR_BRIGHT !== "undefined") {
internal.COLOR_BRIGHT = COLOR_BRIGHT;
delete COLOR_BRIGHT;
}
if (internal.COLOR_OUTPUT) {
internal.COLOR_OUTPUT_DEFAULT = internal.COLOR_BRIGHT;
internal.COLOR_BLACK = COLOR_BLACK;
delete COLOR_BLACK;
internal.COLOR_BOLD_BLACK = COLOR_BOLD_BLACK;
delete COLOR_BOLD_BLACK;
internal.COLOR_BLINK = COLOR_BLINK;
delete COLOR_BLINK;
internal.COLOR_BLUE = COLOR_BLUE;
delete COLOR_BLUE;
internal.COLOR_BOLD_BLUE = COLOR_BOLD_BLUE;
delete COLOR_BOLD_BLUE;
internal.COLOR_GREEN = COLOR_GREEN;
delete COLOR_GREEN;
internal.COLOR_BOLD_GREEN = COLOR_BOLD_GREEN;
delete COLOR_BOLD_GREEN;
internal.COLOR_RED = COLOR_RED;
delete COLOR_RED;
internal.COLOR_BOLD_RED = COLOR_BOLD_RED;
delete COLOR_BOLD_RED;
internal.COLOR_WHITE = COLOR_WHITE;
delete COLOR_WHITE;
internal.COLOR_BOLD_WHITE = COLOR_BOLD_WHITE;
delete COLOR_BOLD_WHITE;
internal.COLOR_YELLOW = COLOR_YELLOW;
delete COLOR_YELLOW;
internal.COLOR_BOLD_YELLOW = COLOR_BOLD_YELLOW;
delete COLOR_BOLD_YELLOW;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleInternal
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief prints objects to standard output
///
/// @FUN{internal.printShell(@FA{arg1}, @FA{arg2}, @FA{arg3}, ...)}
///
/// Only available in shell mode.
///
/// Prints the arguments. If an argument is an object having a
/// function @FN{_PRINT}, then this function is called. Otherwise @FN{toJson} is
/// used. A final newline is printed
///
/// @verbinclude fluent40
////////////////////////////////////////////////////////////////////////////////
internal.printShell = function () {
var i;
for (i = 0; i < arguments.length; ++i) {
if (0 < i) {
internal.output(" ");
}
if (typeof(arguments[i]) === "string") {
internal.output(arguments[i]);
}
else {
internal.printRecursive(arguments[i], [], "~", [], 0);
}
}
if (internal.COLOR_OUTPUT) {
internal.output(internal.COLOR_OUTPUT_DEFAULT);
internal.output(internal.COLOR_OUTPUT_RESET);
}
internal.output("\n");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief quote cache
////////////////////////////////////////////////////////////////////////////////
internal.characterQuoteCache = {
'\b': '\\b', // ASCII 8, Backspace
'\t': '\\t', // ASCII 9, Tab
'\n': '\\n', // ASCII 10, Newline
'\f': '\\f', // ASCII 12, Formfeed
'\r': '\\r', // ASCII 13, Carriage Return
'\"': '\\"',
'\\': '\\\\'
};
////////////////////////////////////////////////////////////////////////////////
/// @brief quotes a single character
////////////////////////////////////////////////////////////////////////////////
internal.quoteSingleJsonCharacter = function (c) {
if (internal.characterQuoteCache.hasOwnProperty[c]) {
return internal.characterQuoteCache[c];
}
var charCode = c.charCodeAt(0);
var result;
if (charCode < 16) {
result = '\\u000';
}
else if (charCode < 256) {
result = '\\u00';
}
else if (charCode < 4096) {
result = '\\u0';
}
else {
result = '\\u';
}
result += charCode.toString(16);
internal.characterQuoteCache[c] = result;
return result;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief quotes a string character
////////////////////////////////////////////////////////////////////////////////
internal.quoteJsonString = function (str) {
var quotable = /[\\\"\x00-\x1f]/g;
return '"' + str.replace(quotable, internal.quoteSingleJsonCharacter) + '"';
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints objects to standard output without a new-line
////////////////////////////////////////////////////////////////////////////////
internal.printRecursive = function (value, seen, path, names, level) {
var p;
if (seen === undefined) {
seen = [];
names = [];
}
p = seen.indexOf(value);
if (0 <= p) {
internal.output(names[p]);
}
else {
if (value instanceof Object) {
seen.push(value);
names.push(path);
}
if (value instanceof Object) {
if (typeof value._PRINT === "function") {
value._PRINT(seen, path, names, level);
}
else if (value instanceof Array) {
internal.printArray(value, seen, path, names, level);
}
else if (value.__proto__ === Object.prototype) {
internal.printObject(value, seen, path, names, level);
}
else if (typeof value.toString === "function") {
internal.output(value.toString());
}
else {
internal.printObject(value, seen, path, names, level);
}
}
else if (value === undefined) {
internal.output("undefined");
}
else {
if (typeof(value) === "string") {
internal.output(internal.quoteJsonString(value));
}
else {
internal.output(String(value));
}
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief JSON representation of an array
////////////////////////////////////////////////////////////////////////////////
internal.printArray = function (object, seen, path, names, level) {
if (object.length === 0) {
internal.output("[ ]");
}
else {
var i;
var sep = "";
internal.output("[");
var newLevel = level + 1;
for (i = 0; i < object.length; i++) {
internal.output(sep);
internal.printIndent(newLevel);
internal.printRecursive(object[i],
seen,
path + "[" + i + "]",
names,
newLevel);
sep = ", ";
}
if (object.length > 1) {
internal.output(" ");
}
internal.printIndent(level);
internal.output("]");
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints an object
////////////////////////////////////////////////////////////////////////////////
internal.printObject = function (object, seen, path, names, level) {
var sep = " ";
var k;
internal.output("{");
var newLevel = level + 1;
for (k in object) {
if (object.hasOwnProperty(k)) {
var val = object[k];
internal.output(sep);
internal.printIndent(newLevel);
if (internal.COLOR_OUTPUT) {
internal.output(internal.COLOR_OUTPUT_DEFAULT);
internal.output(internal.quoteJsonString(k));
internal.output(internal.COLOR_OUTPUT_RESET);
internal.output(" : ");
}
else {
internal.output(internal.quoteJsonString(k), " : ");
}
internal.printRecursive(val,
seen,
path + "[" + k + "]",
names,
newLevel);
sep = ", ";
}
}
if (sep === ", ") {
internal.output(" ");
}
internal.printIndent(level);
internal.output("}");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints the ident for pretty printing
////////////////////////////////////////////////////////////////////////////////
internal.printIndent = function (level) {
var j;
if (internal.PRETTY_PRINT) {
internal.output("\n");
for (j = 0; j < level; ++j) {
internal.output(" ");
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief flushes the module cache
////////////////////////////////////////////////////////////////////////////////
internal.flushModuleCache = function() {
module.unloadAll();
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleInternal
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief global print
////////////////////////////////////////////////////////////////////////////////
internal.print = internal.printShell;
if (typeof internal.printBrowser === "function") {
internal.print = internal.printBrowser;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief start pager
////////////////////////////////////////////////////////////////////////////////
internal.start_pager = function () {};
if (typeof SYS_START_PAGER !== "undefined") {
internal.start_pager = SYS_START_PAGER;
delete SYS_START_PAGER;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief stop pager
////////////////////////////////////////////////////////////////////////////////
internal.stop_pager = function () {};
if (typeof SYS_STOP_PAGER !== "undefined") {
internal.stop_pager = SYS_STOP_PAGER;
delete SYS_STOP_PAGER;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief encode password using SHA256
////////////////////////////////////////////////////////////////////////////////
internal.encodePassword = function (password) {
var salt;
var encoded;
salt = internal.sha256("time:" + internal.time());
salt = salt.substr(0,8);
encoded = "$1$" + salt + "$" + internal.sha256(salt + password);
return encoded;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief extends a prototype
////////////////////////////////////////////////////////////////////////////////
internal.extend = function (target, source) {
Object.getOwnPropertyNames(source)
.forEach(function(propName) {
Object.defineProperty(target, propName,
Object.getOwnPropertyDescriptor(source, propName));
});
return target;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief reads a file from the module path or the database
////////////////////////////////////////////////////////////////////////////////
internal.loadDatabaseFile = function (path) {
var i;
var mc;
var n;
// try to load the file
var paths = internal.MODULES_PATH;
for (i = 0; i < paths.length; ++i) {
var p = paths[i];
if (p === "") {
n = "." + path + ".js";
}
else {
n = p + "/" + path + ".js";
}
if (internal.exists(n)) {
Module.prototype.ModuleExistsCache[path] = true;
return { path : n, content : internal.read(n) };
}
}
// try to load the module from the database
if (internal.db !== undefined) {
mc = internal.db._collection("_modules");
if (mc !== null && typeof mc.firstExample === "function") {
n = mc.firstExample({ path: path });
if (n !== null) {
if (n.hasOwnProperty('content')) {
Module.prototype.ModuleExistsCache[path] = true;
return { path : "_collection/" + path, content : n.content };
}
if (Module.prototype.ModuleExistsCache.hasOwnProperty("/console")) {
var console = Module.prototype.ModuleExistsCache["/console"];
console.error("found empty content in '%s'", JSON.stringify(n));
}
}
}
}
Module.prototype.ModuleExistsCache[path] = false;
throw "cannot find a file named '"
+ path
+ "' using the module path(s) '"
+ internal.MODULES_PATH + "'";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief loads a file from the file-system
////////////////////////////////////////////////////////////////////////////////
internal.loadFile = function (path) {
var i;
// try to load the file
var paths = internal.MODULES_PATH;
for (i = 0; i < paths.length; ++i) {
var p = paths[i];
var n;
if (p === "") {
n = "." + path + ".js";
}
else {
n = p + "/" + path + ".js";
}
if (internal.exists(n)) {
return internal.load(n);
}
}
throw "cannot find a file named '"
+ path
+ "' using the module path(s) '"
+ internal.MODULES_PATH + "'";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief defines a module
////////////////////////////////////////////////////////////////////////////////
internal.defineModule = function (path, file) {
var content;
var m;
var mc;
content = internal.read(file);
mc = internal.db._collection("_modules");
if (mc === null) {
mc = internal.db._create("_modules", { isSystem: true });
}
path = module.normalise(path);
m = mc.firstExample({ path: path });
if (m === null) {
mc.save({ path: path, content: content });
}
else {
mc.replace(m, { path: path, content: content });
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
}());
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -1,17 +1,5 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*global
require, module,
SYS_EXECUTE, CONSOLE_ERROR, FS_MOVE, FS_REMOVE, FS_EXISTS, SYS_LOAD, SYS_LOG,
SYS_LOG_LEVEL, SYS_OUTPUT, SYS_PROCESS_STAT, SYS_READ, SYS_SPRINTF, SYS_TIME,
SYS_START_PAGER, SYS_STOP_PAGER, ARANGO_QUIET, MODULES_PATH, COLOR_OUTPUT,
COLOR_OUTPUT_RESET, COLOR_BRIGHT, PRETTY_PRINT, SYS_SHA256, SYS_WAIT, SYS_GETLINE
*/
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, module: true */
////////////////////////////////////////////////////////////////////////////////
/// @brief JavaScript server functions
@ -63,6 +51,9 @@ function Module (id) {
////////////////////////////////////////////////////////////////////////////////
Module.prototype.ModuleCache = {};
Module.prototype.ModuleCache["/internal"] = new Module("/internal");
Module.prototype.ModuleCache["/fs"] = new Module("/fs");
Module.prototype.ModuleCache["/console"] = new Module("/console");
////////////////////////////////////////////////////////////////////////////////
/// @brief file exists cache
@ -75,6 +66,7 @@ Module.prototype.ModuleExistsCache = {};
////////////////////////////////////////////////////////////////////////////////
Module.prototype.require = function (path) {
var internal;
var content;
var f;
var module;
@ -82,6 +74,8 @@ Module.prototype.require = function (path) {
var raw;
var sandbox;
internal = this.ModuleCache["/internal"].exports;
// first get rid of any ".." and "."
path = this.normalise(path);
@ -91,10 +85,10 @@ Module.prototype.require = function (path) {
}
// locate file and read content
raw = this.ModuleCache["/internal"].exports.readFile(path);
raw = internal.loadDatabaseFile(path);
// test for parse errors first and fail early if a parse error detected
if (! SYS_PARSE(raw.content, path)) {
if (! internal.parse(raw.content, path)) {
throw "Javascript parse error in file '" + path + "'";
}
@ -105,7 +99,7 @@ Module.prototype.require = function (path) {
+ raw.content
+ "\n});";
f = SYS_EXECUTE(content, undefined, path);
f = internal.execute(content, undefined, path);
if (f === undefined) {
throw "cannot create context function";
@ -118,6 +112,7 @@ Module.prototype.require = function (path) {
this.ModuleCache["/internal"].exports.print);
}
catch (err) {
delete this.ModuleCache[path];
throw "Javascript exception in file '" + path + "': " + err.stack;
}
@ -129,8 +124,8 @@ Module.prototype.require = function (path) {
////////////////////////////////////////////////////////////////////////////////
Module.prototype.exists = function (path) {
return this.ModuleExistsCache[path];
}
return Module.prototype.ModuleExistsCache[path];
};
////////////////////////////////////////////////////////////////////////////////
/// @brief normalises a path
@ -194,12 +189,16 @@ Module.prototype.unload = function (path) {
var norm = module.normalise(path);
if ( norm === "/"
|| norm === "/internal"
|| norm === "/console"
|| norm === "/fs") {
|| norm === "/internal"
|| norm === "/fs"
|| norm === "/org/arangodb"
|| norm === "/org/arangodb/actions") {
return;
}
Module.prototype.ModuleCache["/console"].exports.info("UNLOADING %s", path);
delete this.ModuleCache[norm];
};
@ -251,428 +250,19 @@ function require (path) {
}
////////////////////////////////////////////////////////////////////////////////
/// @}
/// @brief global print function
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Module "fs"
// -----------------------------------------------------------------------------
function print () {
var internal = require("internal");
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleFS
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief file-system module
////////////////////////////////////////////////////////////////////////////////
Module.prototype.ModuleCache["/fs"] = new Module("/fs");
(function () {
var fs = Module.prototype.ModuleCache["/fs"].exports;
fs.exists = FS_EXISTS;
fs.move = FS_MOVE;
fs.remove = FS_REMOVE;
}());
internal.print.apply(internal.print, arguments);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- Module "internal"
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleInternal
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief internal module
////////////////////////////////////////////////////////////////////////////////
Module.prototype.ModuleCache["/internal"] = new Module("/internal");
(function () {
var internal = Module.prototype.ModuleCache["/internal"].exports;
var fs = Module.prototype.ModuleCache["/fs"].exports;
// system functions
internal.execute = SYS_EXECUTE;
internal.load = SYS_LOAD;
internal.log = SYS_LOG;
internal.logLevel = SYS_LOG_LEVEL;
internal.output = SYS_OUTPUT;
internal.processStat = SYS_PROCESS_STAT;
internal.read = SYS_READ;
internal.sprintf = SYS_SPRINTF;
internal.time = SYS_TIME;
internal.sha256 = SYS_SHA256;
internal.wait = SYS_WAIT;
// password interface
internal.encodePassword = function (password) {
var salt;
var encoded;
salt = internal.sha256("time:" + SYS_TIME());
salt = salt.substr(0,8);
encoded = "$1$" + salt + "$" + internal.sha256(salt + password);
return encoded;
}
// command line parameter
internal.MODULES_PATH = "";
if (typeof MODULES_PATH !== "undefined") {
internal.MODULES_PATH = MODULES_PATH;
}
// output
internal.start_pager = function () {};
internal.stop_pager = function () {};
internal.ARANGO_QUIET = false;
internal.COLOR_OUTPUT = false;
internal.COLOR_OUTPUT_DEFAULT = "";
internal.COLOR_OUTPUT_RESET = "";
internal.COLOR_BRIGHT = "";
internal.PRETTY_PRINT = false;
if (typeof SYS_START_PAGER !== "undefined") {
internal.start_pager = SYS_START_PAGER;
}
if (typeof SYS_STOP_PAGER !== "undefined") {
internal.stop_pager = SYS_STOP_PAGER;
}
if (typeof COLOR_OUTPUT !== "undefined") {
internal.COLOR_OUTPUT = COLOR_OUTPUT;
}
if (typeof COLOR_OUTPUT_RESET !== "undefined") {
internal.COLOR_OUTPUT_RESET = COLOR_OUTPUT_RESET;
}
if (typeof COLOR_BRIGHT !== "undefined") {
internal.COLOR_BRIGHT = COLOR_BRIGHT;
}
if (typeof PRETTY_PRINT !== "undefined") {
internal.PRETTY_PRINT = PRETTY_PRINT;
}
if (internal.COLOR_OUTPUT) {
internal.COLOR_OUTPUT_DEFAULT = internal.COLOR_BRIGHT;
internal.COLOR_BLACK = COLOR_BLACK;
internal.COLOR_BOLD_BLACK = COLOR_BOLD_BLACK;
internal.COLOR_BLINK = COLOR_BLINK;
internal.COLOR_BLUE = COLOR_BLUE;
internal.COLOR_BOLD_BLUE = COLOR_BOLD_BLUE;
internal.COLOR_BRIGHT = COLOR_BRIGHT;
internal.COLOR_GREEN = COLOR_GREEN;
internal.COLOR_BOLD_GREEN = COLOR_BOLD_GREEN;
internal.COLOR_RED = COLOR_RED;
internal.COLOR_BOLD_RED = COLOR_BOLD_RED;
internal.COLOR_WHITE = COLOR_WHITE;
internal.COLOR_BOLD_WHITE = COLOR_BOLD_WHITE;
internal.COLOR_YELLOW = COLOR_YELLOW;
internal.COLOR_BOLD_YELLOW = COLOR_BOLD_YELLOW;
internal.COLOR_OUTPUT_RESET = COLOR_OUTPUT_RESET;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief extends a prototype
////////////////////////////////////////////////////////////////////////////////
internal.extend = function (target, source) {
Object.getOwnPropertyNames(source)
.forEach(function(propName) {
Object.defineProperty(target, propName,
Object.getOwnPropertyDescriptor(source, propName));
});
return target;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief reads a file from the module path or the database
////////////////////////////////////////////////////////////////////////////////
internal.readFile = function (path) {
var i;
var mc;
var n;
// try to load the file
var paths = internal.MODULES_PATH;
for (i = 0; i < paths.length; ++i) {
var p = paths[i];
if (p === "") {
n = "." + path + ".js";
}
else {
n = p + "/" + path + ".js";
}
if (fs.exists(n)) {
Module.prototype.ModuleExistsCache[path] = true;
return { path : n, content : internal.read(n) };
}
}
// try to load the module from the database
if (internal.db !== undefined) {
mc = internal.db._collection("_modules");
if (mc !== null && ("firstExample" in mc)) {
n = mc.firstExample({ path: path });
if (n !== null) {
if (n.hasOwnProperty('content')) {
Module.prototype.ModuleExistsCache[path] = true;
return { path : "_collection/" + path, content : n.content };
}
else {
require("console").error("found empty content in '%s'", JSON.stringify(n));
}
}
}
}
Module.prototype.ModuleExistsCache[path] = false;
throw "cannot find a file named '"
+ path
+ "' using the module path(s) '"
+ internal.MODULES_PATH + "'";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief loads a file from the file-system
////////////////////////////////////////////////////////////////////////////////
internal.loadFile = function (path) {
var i;
// try to load the file
var paths = internal.MODULES_PATH;
for (i = 0; i < paths.length; ++i) {
var p = paths[i];
var n;
if (p === "") {
n = "." + path + ".js";
}
else {
n = p + "/" + path + ".js";
}
if (fs.exists(n)) {
return internal.load(n);
}
}
throw "cannot find a file named '"
+ path
+ "' using the module path(s) '"
+ internal.MODULES_PATH + "'";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief defines a module
////////////////////////////////////////////////////////////////////////////////
internal.defineModule = function (path, file) {
var content;
var m;
var mc;
content = internal.read(file);
mc = internal.db._collection("_modules");
if (mc === null) {
mc = internal.db._create("_modules", { isSystem: true });
}
path = module.normalise(path);
m = mc.firstExample({ path: path });
if (m === null) {
mc.save({ path: path, module: content });
}
else {
m.module = content;
mc.replace(m, m);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
}());
// -----------------------------------------------------------------------------
// --SECTION-- Module "console"
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8ModuleConsole
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief console module
////////////////////////////////////////////////////////////////////////////////
Module.prototype.ModuleCache["/console"] = new Module("/console");
(function () {
var internal = Module.prototype.ModuleCache["/internal"].exports;
var console = Module.prototype.ModuleCache["/console"].exports;
console.getline = SYS_GETLINE;
////////////////////////////////////////////////////////////////////////////////
/// @brief logs debug message
///
/// @FUN{console.debug(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// debug message.
///
/// String substitution patterns, which can be used in @FA{format}.
///
/// - @LIT{\%s} string
/// - @LIT{\%d}, @LIT{\%i} integer
/// - @LIT{\%f} floating point number
/// - @LIT{\%o} object hyperlink
////////////////////////////////////////////////////////////////////////////////
console.debug = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("debug", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs error message
///
/// @FUN{console.error(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// error message.
////////////////////////////////////////////////////////////////////////////////
console.error = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("error", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs info message
///
/// @FUN{console.info(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// info message.
////////////////////////////////////////////////////////////////////////////////
console.info = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("info", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs log message
///
/// @FUN{console.log(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// log message.
////////////////////////////////////////////////////////////////////////////////
console.log = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("info", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief logs warn message
///
/// @FUN{console.warn(@FA{format}, @FA{argument1}, ...)}
///
/// Formats the arguments according to @FA{format} and logs the result as
/// warn message.
////////////////////////////////////////////////////////////////////////////////
console.warn = function () {
var msg;
try {
msg = internal.sprintf.apply(internal.sprintf, arguments);
}
catch (err) {
msg = err + ": " + arguments;
}
internal.log("warn", msg);
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
}());
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------

View File

@ -1,8 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, plusplus: true */
////////////////////////////////////////////////////////////////////////////////
/// @brief Monkeypatches to built-in prototypes
@ -27,10 +23,20 @@
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Dr. Frank Celler, Lucas Dohmen
/// @author Dr. Frank Celler
/// @author Lucas Dohmen
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- monkey-patches
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Shell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief remove last occurrence of element from an array
////////////////////////////////////////////////////////////////////////////////
@ -90,4 +96,17 @@ Object.defineProperty(Object.prototype, "propertyKeys", {
return (element[0] !== '_' && element[0] !== '$');
});
}
});
});
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -1,338 +0,0 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*global require, print */
////////////////////////////////////////////////////////////////////////////////
/// @brief printing
///
/// @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
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function () {
var internal = require("internal");
// -----------------------------------------------------------------------------
// --SECTION-- Module "internal"
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Shell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief prints objects to standard output
///
/// @FUN{internal.printShell(@FA{arg1}, @FA{arg2}, @FA{arg3}, ...)}
///
/// Only available in shell mode.
///
/// Prints the arguments. If an argument is an object having a
/// function @FN{_PRINT}, then this function is called. Otherwise @FN{toJson} is
/// used. A final newline is printed
///
/// @verbinclude fluent40
////////////////////////////////////////////////////////////////////////////////
internal.printShell = function () {
var i;
for (i = 0; i < arguments.length; ++i) {
if (0 < i) {
internal.output(" ");
}
if (typeof(arguments[i]) === "string") {
internal.output(arguments[i]);
}
else {
internal.printRecursive(arguments[i], [], "~", [], 0);
}
}
if (internal.COLOR_OUTPUT) {
internal.output(internal.COLOR_OUTPUT_DEFAULT);
internal.output(internal.COLOR_OUTPUT_RESET);
}
internal.output("\n");
};
////////////////////////////////////////////////////////////////////////////////
/// @brief quote cache
////////////////////////////////////////////////////////////////////////////////
internal.characterQuoteCache = {
'\b': '\\b', // ASCII 8, Backspace
'\t': '\\t', // ASCII 9, Tab
'\n': '\\n', // ASCII 10, Newline
'\f': '\\f', // ASCII 12, Formfeed
'\r': '\\r', // ASCII 13, Carriage Return
'\"': '\\"',
'\\': '\\\\'
};
////////////////////////////////////////////////////////////////////////////////
/// @brief quotes a single character
////////////////////////////////////////////////////////////////////////////////
internal.quoteSingleJsonCharacter = function (c) {
if (internal.characterQuoteCache.hasOwnProperty[c]) {
return internal.characterQuoteCache[c];
}
var charCode = c.charCodeAt(0);
var result;
if (charCode < 16) {
result = '\\u000';
}
else if (charCode < 256) {
result = '\\u00';
}
else if (charCode < 4096) {
result = '\\u0';
}
else {
result = '\\u';
}
result += charCode.toString(16);
internal.characterQuoteCache[c] = result;
return result;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief quotes a string character
////////////////////////////////////////////////////////////////////////////////
internal.quoteJsonString = function (str) {
var quotable = /[\\\"\x00-\x1f]/g;
return '"' + str.replace(quotable, internal.quoteSingleJsonCharacter) + '"';
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints objects to standard output without a new-line
////////////////////////////////////////////////////////////////////////////////
internal.printRecursive = function (value, seen, path, names, level) {
var p;
if (seen === undefined) {
seen = [];
names = [];
}
p = seen.indexOf(value);
if (0 <= p) {
internal.output(names[p]);
}
else {
if (value instanceof Object) {
seen.push(value);
names.push(path);
}
if (value instanceof Object) {
if ('_PRINT' in value) {
value._PRINT(seen, path, names, level);
}
else if (value instanceof Array) {
internal.printArray(value, seen, path, names, level);
}
else if (value.__proto__ === Object.prototype) {
internal.printObject(value, seen, path, names, level);
}
else if ('toString' in value) {
internal.output(value.toString());
}
else {
internal.printObject(value, seen, path, names, level);
}
}
else if (value === undefined) {
internal.output("undefined");
}
else {
if (typeof(value) === "string") {
internal.output(internal.quoteJsonString(value));
}
else {
internal.output(String(value));
}
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints the ident for pretty printing
///
/// @FUN{internal.printIndent(@FA{level})}
///
/// Only available in shell mode.
////////////////////////////////////////////////////////////////////////////////
internal.printIndent = function (level) {
var j;
if (internal.PRETTY_PRINT) {
internal.output("\n");
for (j = 0; j < level; ++j) {
internal.output(" ");
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief JSON representation of an array
////////////////////////////////////////////////////////////////////////////////
internal.printArray = function (object, seen, path, names, level) {
if (object.length === 0) {
internal.output("[ ]");
}
else {
var i;
var sep = "";
internal.output("[");
var newLevel = level + 1;
for (i = 0; i < object.length; i++) {
internal.output(sep);
internal.printIndent(newLevel);
internal.printRecursive(object[i],
seen,
path + "[" + i + "]",
names,
newLevel);
sep = ", ";
}
if (object.length > 1) {
internal.output(" ");
}
internal.printIndent(level);
internal.output("]");
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief prints an object
////////////////////////////////////////////////////////////////////////////////
internal.printObject = function (object, seen, path, names, level) {
var sep = " ";
var k;
internal.output("{");
var newLevel = level + 1;
for (k in object) {
if (object.hasOwnProperty(k)) {
var val = object[k];
internal.output(sep);
internal.printIndent(newLevel);
if (internal.COLOR_OUTPUT) {
internal.output(internal.COLOR_OUTPUT_DEFAULT);
internal.output(internal.quoteJsonString(k));
internal.output(internal.COLOR_OUTPUT_RESET);
internal.output(" : ");
}
else {
internal.output(internal.quoteJsonString(k), " : ");
}
internal.printRecursive(val,
seen,
path + "[" + k + "]",
names,
newLevel);
sep = ", ";
}
}
if (sep == ", ") {
internal.output(" ");
}
internal.printIndent(level);
internal.output("}");
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
}());
// -----------------------------------------------------------------------------
// --SECTION-- global functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup V8Shell
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief global print
////////////////////////////////////////////////////////////////////////////////
// must be a variable definition for the browser
if (typeof require("internal").printBrowser === "function") {
print = require("internal").print = require("internal").printBrowser;
}
else {
print = require("internal").print = require("internal").printShell;
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
// End:

View File

@ -47,7 +47,7 @@ function RunTest (path, options) {
var content;
try {
content = SYS_READ(path);
content = internal.read(path);
}
catch (err) {
console.error("cannot load test file '%s'", path);

View File

@ -182,10 +182,12 @@
// newcap true, if constructor names capitalization is ignored
// node true, if Node.js globals should be predefined
// nomen true, if names may have dangling _
/// nonpropdel true, if delete should be allowed for non-properties
// on true, if HTML event handlers should be allowed
// passfail true, if the scan should stop on first error
// plusplus true, if increment/decrement should be allowed
// properties true, if all property names must be declared with /*properties*/
// proto true, if __proto__ is allowed
// regexp true, if the . should be allowed in regexp literals
// rhino true, if the Rhino environment globals should be predefined
// undef true, if variables can be declared out of order
@ -274,7 +276,7 @@
'min-height', 'min-width', missing_a, missing_a_after_b, missing_option,
missing_property, missing_space_a_b, missing_url, missing_use_strict, mixed,
mm, mode, move_invocation, move_var, n, name, name_function, nav,
nested_comment, newcap, node, noframes, nomen, noscript, not,
nested_comment, newcap, node, noframes, nomen, nonpropdel, noscript, not,
not_a_constructor, not_a_defined, not_a_function, not_a_label, not_a_scope,
not_greater, nud, number, object, octal_a, ol, on, opacity, open, optgroup,
option, outer, outline, 'outline-color', 'outline-style', 'outline-width',
@ -283,7 +285,7 @@
'page-break-before', param, parameter_a_get_b, parameter_arguments_a,
parameter_set_a, params, paren, parent, passfail, pc, plusplus, pop,
position, postscript, pre, predef, print, progress, projection, properties,
properties_report, property, prototype, pt, push, px, q, quote, quotes, r,
properties_report, property, proto, prototype, pt, push, px, q, quote, quotes, r,
radix, range, raw, read_only, reason, redefinition_a, regexp, replace,
report, reserved, reserved_a, rhino, right, rp, rt, ruby, safe, samp,
scanned_a_b, screen, script, search, second, section, select, shift,
@ -356,10 +358,12 @@ var JSLINT = (function () {
newcap : true,
node : true,
nomen : true,
nonpropdel: true,
on : true,
passfail : true,
plusplus : true,
properties: true,
proto : true,
regexp : true,
rhino : true,
undef : true,
@ -1218,8 +1222,12 @@ var JSLINT = (function () {
)] || syntax['(error)']);
if (type === '(identifier)') {
the_token.identifier = true;
if (value === '__iterator__' || value === '__proto__') {
if (value === '__iterator__') {
stop_at('reserved_a', line, from, value);
} else if (value === '__proto__') {
if (!option.proto) {
stop_at('reserved_a', line, from, value);
}
} else if (!option.nomen &&
(value.charAt(0) === '_' ||
value.charAt(value.length - 1) === '_')) {
@ -3419,8 +3427,10 @@ klass: do {
prefix('delete', function () {
one_space();
var p = expression(0);
if (!p || (p.id !== '.' && p.id !== '[')) {
warn('deleted');
if (!option.nonpropdel) {
if (!p || (p.id !== '.' && p.id !== '[')) {
warn('deleted');
}
}
this.first = p;
return this;

View File

@ -348,10 +348,10 @@ function RunTest (path) {
var content;
var f;
content = SYS_READ(path);
content = internal.read(path);
content = "(function(jsUnity){jsUnity.attachAssertions();" + content + "})";
f = SYS_EXECUTE(content, undefined, path);
f = internal.execute(content, undefined, path);
if (f == undefined) {
throw "cannot create context function";

View File

@ -38,7 +38,6 @@
var internal = require("internal");
var console = require("console");
var ArangoDatabase = internal.ArangoDatabase;
var ArangoCollection = internal.ArangoCollection;
var ArangoError = internal.ArangoError;
@ -121,7 +120,7 @@
/// in a production environment.
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.toArray = function() {
ArangoCollection.prototype.toArray = function () {
return this.ALL(null, null).documents;
};
@ -137,10 +136,20 @@
///
/// Truncates a collection:
///
/// @verbinclude shell_collection-truncate
/// @code
/// arango> col = db.examples;
/// [ArangoCollection 91022, "examples" (status new born)]
/// arango> col.save({ "Hallo" : "World" });
/// { "_id" : "91022/1532814", "_rev" : 1532814 }
/// arango> col.count();
/// 1
/// arango> col.truncate();
/// arango> col.count();
/// 0
/// @endcode
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.truncate = function() {
ArangoCollection.prototype.truncate = function () {
return internal.db._truncate(this);
};
@ -153,10 +162,15 @@
///
/// @EXAMPLES
///
/// @verbinclude shell_index-read
/// @code
/// arango> db.example.getIndexes().map(function(x) { return x.id; });
/// ["93013/0"]
/// arango> db.example.index("93013/0");
/// { "id" : "93013/0", "type" : "primary", "fields" : ["_id"] }
/// @endcode
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.index = function(id) {
ArangoCollection.prototype.index = function (id) {
var indexes = this.getIndexes();
var i;
@ -182,14 +196,141 @@
return null;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief iterators over some elements of a collection
///
/// @FUN{@FA{collection}.iterate(@FA{iterator}, @FA{options})}
///
/// Iterates over some elements of the collection and apply the function
/// @FA{iterator} to the elements. The function will be called with the
/// document as first argument and the current number (starting with 0)
/// as second argument.
///
/// @FA{options} must be an object with the following attributes:
///
/// - @LIT{limit} (optional, default none): use at most @LIT{limit} documents.
///
/// - @LIT{probability} (optional, default all): a number between @LIT{0} and
/// @LIT{1}. Documents are chosen with this probability.
///
/// @EXAMPLES
///
/// @code
/// arango> db.example.getIndexes().map(function(x) { return x.id; });
/// ["93013/0"]
/// arango> db.example.index("93013/0");
/// { "id" : "93013/0", "type" : "primary", "fields" : ["_id"] }
/// @endcode
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.iterate = function (iterator, options) {
var probability = 1.0;
var limit = null;
var stmt;
var cursor;
var pos;
if (options !== undefined) {
if (options.hasOwnProperty("probability")) {
probability = options.probability;
}
if (options.hasOwnProperty("limit")) {
limit = options.limit;
}
}
if (limit === null) {
if (probability >= 1.0) {
stmt = internal.sprintf("FOR d IN %s RETURN d", this.name());
}
else {
stmt = internal.sprintf("FOR d IN %s FILTER rand() >= @prob RETURN d", this.name());
}
}
else {
if (typeof limit !== "number") {
var error = new ArangoError();
error.errorNum = internal.errors.ERROR_ILLEGAL_NUMBER.code;
error.errorMessage = "expecting a number, got " + String(limit);
throw error;
}
if (probability >= 1.0) {
stmt = internal.sprintf("FOR d IN %s LIMIT %d RETURN d", this.name(), limit);
}
else {
stmt = internal.sprintf("FOR d IN %s FILTER rand() >= @prob LIMIT %d RETURN d",
this.name(), limit);
}
}
stmt = internal.db._createStatement({ query: stmt });
if (probability < 1.0) {
stmt.bind("prob", probability);
}
cursor = stmt.execute();
pos = 0;
while (cursor.hasNext()) {
var document = cursor.next();
iterator(document, pos);
pos++;
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief string representation of a collection
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.toString = function(seen, path, names, level) {
ArangoCollection.prototype.toString = function (seen, path, names, level) {
return "[ArangoCollection " + this._id + "]";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief removes documents matching an example
///
/// @FUN{@FA{collection}.removeByExample(@FA{example})}
///
/// Removes all document matching an example.
///
/// @FUN{@FA{collection}.removeByExample(@FA{document}, @FA{waitForSync})}
///
/// The optional @FA{waitForSync} parameter can be used to force synchronisation
/// of the document deletion operation to disk even in case that the
/// @LIT{waitForSync} flag had been disabled for the entire collection. Thus,
/// the @FA{waitForSync} parameter can be used to force synchronisation of just
/// specific operations. To use this, set the @FA{waitForSync} parameter to
/// @LIT{true}. If the @FA{waitForSync} parameter is not specified or set to
/// @LIT{false}, then the collection's default @LIT{waitForSync} behavior is
/// applied. The @FA{waitForSync} parameter cannot be used to disable
/// synchronisation for collections that have a default @LIT{waitForSync} value
/// of @LIT{true}.
///
/// @EXAMPLES
///
/// @code
/// arangod> db.content.removeByExample({ "domain": "de.celler" })
/// @endcode
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype.removeByExample = function (example, waitForSync) {
var documents;
documents = this.byExample(example);
while (documents.hasNext()) {
var document = documents.next();
this.remove(document, true, waitForSync);
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -207,7 +348,7 @@
/// @brief prints a collection
////////////////////////////////////////////////////////////////////////////////
ArangoCollection.prototype._PRINT = function() {
ArangoCollection.prototype._PRINT = function () {
var status = "unknown";
var type = "unknown";

View File

@ -0,0 +1,625 @@
////////////////////////////////////////////////////////////////////////////////
/// @brief ArangoTraverser
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2011-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 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
(function () {
var internal = require("internal"),
console = require("console");
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoTraverser
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief traversal constructor
////////////////////////////////////////////////////////////////////////////////
function ArangoTraverser (edgeCollection,
visitor,
filter,
expander) {
if (typeof edgeCollection === "string") {
edgeCollection = internal.db._collection(edgeCollection);
}
if (! (edgeCollection instanceof ArangoCollection) ||
edgeCollection.type() != internal.ArangoCollection.TYPE_EDGE) {
throw "invalid edgeCollection";
}
// properties
this._edgeCollection = edgeCollection;
// callbacks
this._visitor = visitor;
this._filter = filter || IncludeAllFilter;
this._expander = expander || OutboundExpander;
if (typeof this._visitor !== "function") {
throw "invalid visitor";
}
if (typeof this._filter !== "function") {
throw "invalid filter";
}
if (typeof this._expander !== "function") {
throw "invalid expander";
}
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoTraverser
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief execute the traversal
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.prototype.traverse = function (startVertex,
visitationStrategy,
uniqueness,
context,
state) {
// check the start vertex
if (startVertex == undefined) {
throw "invalid startVertex specified for traversal";
}
if (typeof startVertex == "string") {
startVertex = internal.db._document(startVertex);
}
// check the visitation strategy
if (visitationStrategy !== ArangoTraverser.BREADTH_FIRST &&
visitationStrategy !== ArangoTraverser.DEPTH_FIRST_PRE &&
visitationStrategy !== ArangoTraverser.DEPTH_FIRST_POST) {
throw "invalid visitationStrategy";
}
// set user defined context & state
this._context = context;
this._state = state;
// initialise the traversal strategy
var levelState = InitLevelState(startVertex, function () {
if (visitationStrategy === ArangoTraverser.BREADTH_FIRST) {
return BreadthFirstSearch();
}
else if (visitationStrategy === ArangoTraverser.DEPTH_FIRST_PRE) {
return DepthFirstPreSearch();
}
else {
return DepthFirstPostSearch();
}
}());
// initialise uniqueness check attributes
var uniquenessCheck = {
vertices: uniqueness.vertices || ArangoTraverser.UNIQUE_NONE,
edges: uniqueness.edges || ArangoTraverser.UNIQUE_NONE
};
// now execute the actual traversal...
// iterate until we find the end
while (true) {
var currentElement = levelState.currentElement();
var edge = currentElement.edge;
var vertex = currentElement.vertex;
if (! ProcessVertex(this, vertex, levelState)) {
// stop traversal because PRUNE was returned
return;
}
if (! levelState.next(this, levelState)) {
// we're done
return;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoTraverser
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief initialise some internal state for the traversal
////////////////////////////////////////////////////////////////////////////////
function InitLevelState (startVertex, strategy) {
return {
level: 0,
maxLevel: 0,
index: 0,
positions: [ 0 ],
stack: [ [ { edge: null, vertex: startVertex, parentIndex: 0 } ] ],
path: { edges: [ ], vertices: [ startVertex ] },
visited: { edges: { }, vertices: { } },
next: function (traverser) {
return strategy.next(traverser, this);
},
currentElement: function () {
return strategy.currentElement(this);
},
elementAt: function (searchLevel, searchIndex) {
return this.stack[searchLevel][searchIndex];
},
numElements: function () {
return this.stack[this.level].length;
},
canDescend: function () {
if (this.level >= this.maxLevel) {
return false;
}
return (this.stack[this.level + 1].length > 0);
},
isUniqueVertex: function (checkMode, vertex) {
return this.isUnique(checkMode, this.visited.vertices, vertex._id);
},
isUniqueEdge: function (checkMode, edge) {
return this.isUnique(checkMode, this.visited.edges, edge._id);
},
isUnique: function (checkMode, elementsSeen, element) {
if (checkMode === ArangoTraverser.UNIQUE_NONE) {
return true;
}
var seen = elementsSeen[element] || false;
if (! seen) {
// now mark the element as being visited
elementsSeen[element] = true;
}
return ! seen;
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief implementation details for breadth-first strategy
////////////////////////////////////////////////////////////////////////////////
function BreadthFirstSearch () {
return {
// TODO: ADD UNIQUENESS CHECK HERE
next: function (traverser, levelState) {
var currentElement = levelState.elementAt(levelState.level, levelState.index);
traverser._visitor(traverser, currentElement.vertex, levelState.path);
if (++levelState.index >= levelState.numElements()) {
levelState.index = 0;
if (++levelState.level > levelState.maxLevel) {
// we're done
return false;
}
}
return true;
},
currentElement : function (levelState) {
var path = levelState.path;
var currentElement = levelState.elementAt(levelState.level, levelState.index);
var element = currentElement;
for (var i = levelState.level; i > 0; --i) {
path.edges[i - 1] = element.edge;
path.vertices[i] = element.vertex;
element = levelState.elementAt(i - 1, element.parentIndex);
}
return currentElement;
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief implementation details for depth-first strategy
////////////////////////////////////////////////////////////////////////////////
function DepthFirstPreSearch () {
return {
next: function (traverser, levelState) {
var position = levelState.positions[levelState.level];
var currentElement = levelState.elementAt(levelState.level, position);
traverser._visitor(traverser, currentElement.vertex, levelState.path);
if (levelState.canDescend()) {
++levelState.level;
}
else {
while (++levelState.positions[levelState.level] >= levelState.numElements()) {
levelState.positions[levelState.level] = 0;
delete levelState.stack[levelState.level];
levelState.path.vertices.pop();
levelState.path.edges.pop();
if (levelState.level <= 1) {
// we're done
return false;
}
levelState.level--;
// TODO: make this a function
levelState.maxLevel--;
}
}
var currentElement = levelState.stack[levelState.level][levelState.positions[levelState.level]];
levelState.path.edges[levelState.level - 1] = currentElement.edge;
levelState.path.vertices[levelState.level] = currentElement.vertex;
return true;
},
currentElement : function (levelState) {
var position = levelState.positions[levelState.level];
var currentElement = levelState.elementAt(levelState.level, position);
return currentElement;
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief implementation details for depth-first strategy
////////////////////////////////////////////////////////////////////////////////
function DepthFirstPostSearch () {
return {
next: function (traverser, levelState) {
var currentElement = levelState.stack[levelState.level][levelState.positions[levelState.level]];
console.log("level " + levelState.level + ", ele: " + currentElement.vertex._id);
while (levelState.canDescend()) {
++levelState.level;
var currentElement = levelState.stack[levelState.level][levelState.positions[levelState.level]];
console.log("desc, up is " + currentElement.vertex._id);
levelState.path.edges[levelState.level - 1] = currentElement.edge;
levelState.path.vertices[levelState.level] = currentElement.vertex;
}
while (++levelState.positions[levelState.level] >= levelState.numElements()) {
console.log("undesc");
levelState.positions[levelState.level] = 0;
delete levelState.stack[levelState.level];
if (levelState.level == 0) {
// we're done
return false;
}
levelState.level--;
// TODO: make this a function
levelState.maxLevel--;
// break;
}
var currentElement = levelState.stack[levelState.level][levelState.positions[levelState.level]];
levelState.path.edges[levelState.level - 1] = currentElement.edge;
levelState.path.vertices[levelState.level] = currentElement.vertex;
traverser._visitor(traverser, currentElement.vertex, levelState.path);
return true;
},
currentElement : function (levelState) {
var position = levelState.positions[levelState.level];
var currentElement = levelState.elementAt(levelState.level, position);
return currentElement;
}
};
}
////////////////////////////////////////////////////////////////////////////////
/// @brief callback function that is executed for each vertex found
///
/// this function is applying the filter criteria and calls the visitor
/// function for the vertex if it should be included in the traversal.
/// it will then also fetch the connected edges for the vertex.
////////////////////////////////////////////////////////////////////////////////
function ProcessVertex (traverser, vertex, levelState) {
// check filter condition for vertex
var filterResult = traverser._filter(traverser, vertex, levelState.path);
if (filterResult === ArangoTraverser.INCLUDE_AND_CONTINUE ||
filterResult === ArangoTraverser.INCLUDE_AND_PRUNE) {
// get connected edges for vertex
traverser._expander(traverser, vertex, levelState.path).forEach(function (connection) {
var nextLevel = levelState.level + 1;
if (levelState.stack[nextLevel] == undefined) {
levelState.stack[nextLevel] = [ ];
levelState.positions[nextLevel] = 0;
}
if (levelState.stack[nextLevel].length == 0) {
++levelState.maxLevel;
}
connection.parentIndex = levelState.index;
levelState.stack[nextLevel].push(connection);
});
}
// return true only if we should continue
return (filterResult === ArangoTraverser.INCLUDE_AND_CONTINUE ||
filterResult === ArangoTraverser.EXCLUDE_AND_CONTINUE);
};
////////////////////////////////////////////////////////////////////////////////
/// @brief default filter function (if none specified)
///
/// this filter will simply include every vertex
////////////////////////////////////////////////////////////////////////////////
function IncludeAllFilter (traverser, vertex, path) {
return ArangoTraverser.INCLUDE_AND_CONTINUE;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief default outbound expander function
////////////////////////////////////////////////////////////////////////////////
function OutboundExpander (traverser, vertex, path) {
var connections = [ ];
this._edgeCollection.outEdges(vertex._id).forEach(function (edge) {
var vertex = internal.db._document(edge._to);
connections.push({ edge: edge, vertex: vertex });
});
return connections;
};
////////////////////////////////////////////////////////////////////////////////
/// @brief default inbound expander function
////////////////////////////////////////////////////////////////////////////////
function InboundExpander (traverser, vertex, path) {
var connections = [ ];
this._edgeCollection.inEdges(vertex._id).forEach(function (edge) {
var vertex = internal.db._document(edge._from);
connections.push({ edge: edge, vertex: vertex });
});
return connections;
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- public constants
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoTraverser
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief pre-order visits
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.VISIT_PREORDER = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief post-order visits
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.VISIT_POSTORDER = 1;
////////////////////////////////////////////////////////////////////////////////
/// @brief element may be revisited
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.UNIQUE_NONE = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief element can only be revisited if not already in current path
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.UNIQUE_PATH = 1;
////////////////////////////////////////////////////////////////////////////////
/// @brief element can only be revisited if not already visited
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.UNIQUE_GLOBAL = 2;
////////////////////////////////////////////////////////////////////////////////
/// @brief visitation strategy breadth first
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.UNIQUE_NONE = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief visitation strategy breadth first
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.BREADTH_FIRST = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief visitation strategy depth first
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.DEPTH_FIRST_PRE = 1;
ArangoTraverser.DEPTH_FIRST_POST = 2;
////////////////////////////////////////////////////////////////////////////////
/// @brief include this node in the result and continue the traversal
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.INCLUDE_AND_CONTINUE = 0;
////////////////////////////////////////////////////////////////////////////////
/// @brief include this node in the result, but dont continue the traversal
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.INCLUDE_AND_PRUNE = 1;
////////////////////////////////////////////////////////////////////////////////
/// @brief exclude this node from the result, but continue the traversal
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.EXCLUDE_AND_CONTIUE = 2;
////////////////////////////////////////////////////////////////////////////////
/// @brief exclude this node from the result and dont continue the traversal
////////////////////////////////////////////////////////////////////////////////
ArangoTraverser.EXCLUDE_AND_PRUNE = 3;
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
var stringifyPath = function (path) {
var result = "[";
for (var i = 0; i < path.edges.length; ++i) {
if (i > 0) {
result += ", ";
}
result += path.edges[i].what;
}
result += " ]";
return result;
}
var context = { someContext : true };
var state = { someState : { } };
var visitor = function (traverser, vertex, path) {
var result = path.edges.length + " ";
for (var i = 0; i < path.edges.length; ++i) {
result += " ";
}
result += "- " + vertex._id + " " + stringifyPath(path);
console.log(result);
};
var uniqueness = { vertices : ArangoTraverser.UNIQUE_GLOBAL, edges : ArangoTraverser.UNIQUE_NONE };
db.tusers.load();
db.trelations.load();
var traverser = new ArangoTraverser("trelations", visitor);
traverser.traverse("tusers/claudius", ArangoTraverser.DEPTH_FIRST_PRE, uniqueness, context, state);
console.log("------------");
var traverser = new ArangoTraverser("trelations", visitor);
traverser.traverse("tusers/claudius", ArangoTraverser.DEPTH_FIRST_POST, uniqueness, context, state);
console.log("------------");
var traverser = new ArangoTraverser("trelations", visitor);
traverser.traverse("tusers/claudius", ArangoTraverser.BREADTH_FIRST, uniqueness, context, state);
}());
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- MODULE EXPORTS
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoTraverser
/// @{
////////////////////////////////////////////////////////////////////////////////
/*
exports.ArangoTraverser = ArangoTraverser;
exports.ArangoIncludeAllFilter = IncludeAllFilter;
exports.ArangoOutboundExpander = OutboundExpander;
exports.ArangoInboundExpander = InboundExpander;
*/
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:

14
js/server/ahuacatl.js Executable file → Normal file
View File

@ -2125,15 +2125,14 @@ function AHUACATL_GEO_WITHIN () {
////////////////////////////////////////////////////////////////////////////////
function AHUACATL_GRAPH_PATHS () {
var vertices = arguments[0];
var vertices = arguments[0];
var edgeCollection = arguments[1];
var direction = arguments[2] != undefined ? arguments[2] : "outbound";
var followCycles = arguments[3] ? arguments[3] : false;
var minLength = 0;
var maxLength = 10;
var direction = arguments[2] || "outbound";
var followCycles = arguments[3] || false;
var minLength = arguments[4] || 0;
var maxLength = arguments[5] != undefined ? arguments[5] : 10;
var searchDirection;
AHUACATL_LIST(vertices);
// validate arguments
@ -2145,7 +2144,6 @@ function AHUACATL_GRAPH_PATHS () {
}
else if (direction == "any") {
searchDirection = 3;
maxLength = 3;
}
else {
AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "PATHS");

View File

@ -1,10 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
@ -47,6 +41,18 @@ var internal = require("internal");
exports.db = internal.db;
exports.ArangoCollection = internal.ArangoCollection;
exports.ArangoError = internal.ArangoError;
// copy error codes
(function () {
var name;
for (name in internal.errors) {
if (internal.errors.hasOwnProperty(name)) {
exports[name] = internal.errors[name].code;
}
}
}());
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -1,10 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, regexp: true plusplus: true */
/*global require, exports, module */
////////////////////////////////////////////////////////////////////////////////
@ -34,8 +28,10 @@
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var internal = require("internal");
var console = require("console");
var moduleExists = function(name) { return module.exists; };
// -----------------------------------------------------------------------------
// --SECTION-- private variables
@ -195,6 +191,7 @@ function lookupCallbackStatic (content) {
type = content.contentType || "text/plain";
body = content.body || "";
methods = content.methods || [ exports.GET, exports.HEAD ];
options = content.options || {};
}
return {
@ -245,11 +242,12 @@ function lookupCallbackAction (route, action) {
func = module[name];
}
else {
func = notImplementedFunction(route, "could not find action named '" + name + "' in module '" + joined + "'");
func = notImplementedFunction(route, "could not find action named '"
+ name + "' in module '" + joined + "'");
}
}
catch (err) {
if (! module.exists(joined)) {
if (! moduleExists(joined)) {
func = notImplementedFunction(route,
"an error occurred while loading action named '" + name
+ "' in module '" + joined + "': " + String(err));
@ -280,19 +278,19 @@ function lookupCallbackAction (route, action) {
return {
controller: function (req, res, options, next) {
var m;
// enum all HTTP methods
for (var m in httpMethods) {
if (! httpMethods.hasOwnProperty(m)) {
continue;
}
for (m in httpMethods) {
if (httpMethods.hasOwnProperty(m)) {
if (req.requestType === httpMethods[m] && module.hasOwnProperty(m)) {
func = module[m]
|| errorFunction(route,
"invalid definition for " + m + " action in action controller module '"
+ action.controller + "'");
if (req.requestType == httpMethods[m] && module.hasOwnProperty(m)) {
func = module[m]
|| errorFunction(route,
"invalid definition for " + m + " action in action controller module '"
+ action.controller + "'");
return func(req, res, options, next);
return func(req, res, options, next);
}
}
}
@ -311,16 +309,16 @@ function lookupCallbackAction (route, action) {
methods: action.methods || exports.ALL_METHODS
};
}
catch (err) {
if (! module.exists(action.controller)) {
catch (err1) {
if (! moduleExists(action.controller)) {
return notImplementedFunction(route,
"cannot load/execute action controller module '"
+ action.controller + ": " + String(err));
+ action.controller + ": " + String(err1));
}
return errorFunction(route,
"cannot load/execute action controller module '"
+ action.controller + ": " + String(err));
+ action.controller + ": " + String(err1));
}
}
@ -348,27 +346,28 @@ function lookupCallbackAction (route, action) {
catch (err) {
efunc = errorFunction;
if (! module.exists(path)) {
if (! moduleExists(path)) {
efunc = notImplementedFunction;
}
return efunc(route, "cannot load prefix controller: " + String(err))(req, res, options, next);
return efunc(route, "cannot load prefix controller: " + String(err))(
req, res, options, next);
}
try {
var m;
// enum all HTTP methods
for (var m in httpMethods) {
if (! httpMethods.hasOwnProperty(m)) {
continue;
}
for (m in httpMethods) {
if (httpMethods.hasOwnProperty(m)) {
if (req.requestType === httpMethods[m] && module.hasOwnProperty(m)) {
func = module[m]
|| errorFunction(route,
"Invalid definition for " + m + " action in prefix controller '"
+ action.prefixController + "'");
if (req.requestType == httpMethods[m] && module.hasOwnProperty(m)) {
func = module[m]
|| errorFunction(route,
"Invalid definition for " + m + " action in prefix controller '"
+ action.prefixController + "'");
return func(req, res, options, next);
return func(req, res, options, next);
}
}
}
@ -381,10 +380,11 @@ function lookupCallbackAction (route, action) {
return func(req, res, options, next);
}
}
catch (err) {
catch (err2) {
return errorFunction(route,
"Cannot load/execute prefix controller '"
+ action.prefixController + "': " + String(err))(req, res, options, next);
+ action.prefixController + "': " + String(err2))(
req, res, options, next);
}
next();
@ -454,7 +454,7 @@ function defineRoutePart (route, subwhere, parts, pos, constraint, callback) {
var ok;
part = parts[pos];
if (part == undefined) {
if (part === undefined) {
// otherwise we'll get an exception below
part = '';
}
@ -558,15 +558,20 @@ function flattenRouting (routes, path, urlParameters, depth, prefix) {
var cur;
var i;
var k;
var newUrlParameters;
var parameter;
var match;
var result = [];
if (routes.hasOwnProperty('exact')) {
for (k in routes.exact) {
if (routes.exact.hasOwnProperty(k)) {
newUrlParameters = urlParameters.shallowCopy;
cur = path + "/" + k.replace(/([\.\+\*\?\^\$\(\)\[\]])/g, "\\$1");
result = result.concat(flattenRouting(routes.exact[k],
cur,
urlParameters.shallowCopy,
newUrlParameters,
depth + 1,
false));
}
@ -575,14 +580,14 @@ function flattenRouting (routes, path, urlParameters, depth, prefix) {
if (routes.hasOwnProperty('parameters')) {
for (i = 0; i < routes.parameters.length; ++i) {
var parameter = routes.parameters[i];
var newUrlParameters = urlParameters.shallowCopy;
var match;
parameter = routes.parameters[i];
newUrlParameters = urlParameters.shallowCopy;
if (parameter.hasOwnProperty('constraint')) {
var constraint = parameter.constraint;
var pattern = /\/.*\//;
if (/\/.*\//.test(constraint)) {
if (pattern.test(constraint)) {
match = "/" + constraint.substr(1, constraint.length - 2);
}
else {
@ -804,20 +809,25 @@ function getErrorMessage (code) {
function getJsonBody (req, res, code) {
var body;
var err;
try {
body = JSON.parse(req.requestBody || "{}") || {};
}
catch (err) {
exports.resultBad(req, res, exports.ERROR_HTTP_CORRUPTED_JSON, err);
catch (err1) {
exports.resultBad(req, res, arangodb.ERROR_HTTP_CORRUPTED_JSON, err1);
return undefined;
}
if (! body || ! (body instanceof Object)) {
if (code === undefined) {
code = exports.ERROR_HTTP_CORRUPTED_JSON;
code = arangodb.ERROR_HTTP_CORRUPTED_JSON;
}
err = new internal.ArangoError();
err.errorNum = code;
err.errorMessage = "expecting a valid JSON object as body";
exports.resultBad(req, res, code, err);
return undefined;
}
@ -841,6 +851,7 @@ function getJsonBody (req, res, code) {
function resultError (req, res, httpReturnCode, errorNum, errorMessage, headers, keyvals) {
var i;
var msg;
res.responseCode = httpReturnCode;
res.contentType = "application/json; charset=utf-8";
@ -852,6 +863,13 @@ function resultError (req, res, httpReturnCode, errorNum, errorMessage, headers,
errorNum = httpReturnCode;
}
if (errorMessage === undefined || errorMessage === null) {
msg = getErrorMessage(errorNum);
}
else {
msg = String(errorMessage);
}
var result = {};
if (keyvals !== undefined) {
@ -862,10 +880,10 @@ function resultError (req, res, httpReturnCode, errorNum, errorMessage, headers,
}
}
result["error"] = true;
result["code"] = httpReturnCode;
result["errorNum"] = errorNum;
result["errorMessage"] = errorMessage;
result.error = true;
result.code = httpReturnCode;
result.errorNum = errorNum;
result.errorMessage = msg;
res.body = JSON.stringify(result);
@ -1087,7 +1105,8 @@ function firstRouting (type, parts) {
////////////////////////////////////////////////////////////////////////////////
function badParameter (req, res, name) {
resultError(req, res, exports.HTTP_BAD, exports.HTTP_BAD, "invalid value for parameter '" + name + "'");
resultError(req, res, exports.HTTP_BAD, exports.HTTP_BAD,
"invalid value for parameter '" + name + "'");
}
////////////////////////////////////////////////////////////////////////////////
@ -1130,13 +1149,6 @@ function resultOk (req, res, httpReturnCode, result, headers) {
////////////////////////////////////////////////////////////////////////////////
function resultBad (req, res, code, msg, headers) {
if (msg === undefined || msg === null) {
msg = getErrorMessage(code);
}
else {
msg = String(msg);
}
resultError(req, res, exports.HTTP_BAD, code, msg, headers);
}
@ -1149,7 +1161,7 @@ function resultBad (req, res, code, msg, headers) {
////////////////////////////////////////////////////////////////////////////////
function resultNotFound (req, res, code, msg, headers) {
resultError(req, res, exports.HTTP_NOT_FOUND, code, String(msg), headers);
resultError(req, res, exports.HTTP_NOT_FOUND, code, msg, headers);
}
////////////////////////////////////////////////////////////////////////////////
@ -1164,8 +1176,8 @@ function resultNotImplemented (req, res, msg, headers) {
resultError(req,
res,
exports.HTTP_NOT_IMPLEMENTED,
exports.ERROR_NOT_IMPLEMENTED,
String(msg),
arangodb.ERROR_NOT_IMPLEMENTED,
msg,
headers);
}
@ -1179,7 +1191,8 @@ function resultNotImplemented (req, res, msg, headers) {
function resultUnsupported (req, res, headers) {
resultError(req, res,
exports.HTTP_METHOD_NOT_ALLOWED, exports.ERROR_HTTP_METHOD_NOT_ALLOWED,
exports.HTTP_METHOD_NOT_ALLOWED,
arangodb.ERROR_HTTP_METHOD_NOT_ALLOWED,
"Unsupported method",
headers);
}
@ -1300,11 +1313,11 @@ function resultCursor (req, res, cursor, code, options) {
};
if (cursorId) {
result["id"] = cursorId;
result.id = cursorId;
}
if (hasCount) {
result["count"] = count;
result.count = count;
}
if (code === undefined) {
@ -1325,13 +1338,13 @@ function resultCursor (req, res, cursor, code, options) {
function collectionNotFound (req, res, collection, headers) {
if (collection === undefined) {
resultError(req, res,
exports.HTTP_BAD, exports.ERROR_HTTP_BAD_PARAMETER,
exports.HTTP_BAD, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expecting a collection name or identifier",
headers);
}
else {
resultError(req, res,
exports.HTTP_NOT_FOUND, exports.ERROR_ARANGO_COLLECTION_NOT_FOUND,
exports.HTTP_NOT_FOUND, arangodb.ERROR_ARANGO_COLLECTION_NOT_FOUND,
"unknown collection '" + collection + "'", headers);
}
}
@ -1347,19 +1360,19 @@ function collectionNotFound (req, res, collection, headers) {
function indexNotFound (req, res, collection, index, headers) {
if (collection === undefined) {
resultError(req, res,
exports.HTTP_BAD, exports.ERROR_HTTP_BAD_PARAMETER,
exports.HTTP_BAD, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expecting a collection name or identifier",
headers);
}
else if (index === undefined) {
resultError(req, res,
exports.HTTP_BAD, exports.ERROR_HTTP_BAD_PARAMETER,
exports.HTTP_BAD, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expecting an index identifier",
headers);
}
else {
resultError(req, res,
exports.HTTP_NOT_FOUND, exports.ERROR_ARANGO_INDEX_NOT_FOUND,
exports.HTTP_NOT_FOUND, arangodb.ERROR_ARANGO_INDEX_NOT_FOUND,
"unknown index '" + index + "'", headers);
}
}
@ -1373,20 +1386,20 @@ function indexNotFound (req, res, collection, index, headers) {
////////////////////////////////////////////////////////////////////////////////
function resultException (req, res, err, headers) {
if (err instanceof ArangoError) {
if (err instanceof internal.ArangoError) {
var num = err.errorNum;
var msg = err.errorMessage;
var code = exports.HTTP_BAD;
switch (num) {
case exports.ERROR_INTERNAL: code = exports.HTTP_SERVER_ERROR; break;
case arangodb.ERROR_INTERNAL: code = exports.HTTP_SERVER_ERROR; break;
}
resultError(req, res, code, num, msg, headers);
}
else {
resultError(req, res,
exports.HTTP_SERVER_ERROR, exports.ERROR_HTTP_SERVER_ERROR,
exports.HTTP_SERVER_ERROR, arangodb.ERROR_HTTP_SERVER_ERROR,
String(err),
headers);
}
@ -1570,15 +1583,6 @@ exports.HTTP_NOT_IMPLEMENTED = 501;
exports.HTTP_BAD_GATEWAY = 502;
exports.HTTP_SERVICE_UNAVAILABLE = 503;
// copy error codes
var name;
for (name in internal.errors) {
if (internal.errors.hasOwnProperty(name)) {
exports[name] = internal.errors[name].code;
}
}
// load routing
reloadRouting();

View File

@ -1,5 +1,8 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
/// @brief example controller
/// @brief example echo controller
///
/// @file
///
@ -27,17 +30,17 @@
var actions = require("org/arangodb/actions");
exports.head = function (req, res, next, options) {
exports.head = function (req, res, options, next) {
res.responseCode = actions.HTTP_OK;
res.contentType = "application/json; charset=utf-8";
res.body = "";
}
};
exports.do = function (req, res, next, options) {
exports['do'] = function (req, res, options, next) {
res.responseCode = actions.HTTP_OK;
res.contentType = "application/json; charset=utf-8";
res.body = JSON.stringify( { "request" : req, "options" : options });
}
};
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE

View File

@ -0,0 +1,135 @@
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
/// @brief deliver static content from collection
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 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
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
var actions = require("org/arangodb/actions");
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoActions
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief locate content from collection
////////////////////////////////////////////////////////////////////////////////
function locateContent (req, options) {
var path;
var collection;
if (! options.hasOwnProperty("contentCollection")) {
return null;
}
collection = arangodb.db._collection(options.contentCollection);
if (collection === null) {
return null;
}
path = "/" + req.suffix.join("/");
return collection.firstExample({
path: path,
prefix: options.prefix,
application: options.application });
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoActions
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief locate content from collection
////////////////////////////////////////////////////////////////////////////////
exports.head = function (req, res, options, next) {
var content;
content = locateContent(req, options);
if (content === null) {
res.responseCode = actions.HTTP_NOT_IMPLEMENTED;
res.contentType = "text/plain";
}
else {
res.responseCode = actions.HTTP_OK;
res.contentType = content.contentType || "text/html";
}
res.body = "";
};
////////////////////////////////////////////////////////////////////////////////
/// @brief get request
////////////////////////////////////////////////////////////////////////////////
exports.get = function (req, res, options, next) {
var content;
content = locateContent(req, options);
if (content === null) {
res.responseCode = actions.HTTP_NOT_IMPLEMENTED;
res.contentType = "text/plain";
res.body = "path '" + req.suffix.join("/") + "' not implemented";
}
else {
res.responseCode = actions.HTTP_OK;
res.contentType = content.contentType || "text/html";
res.body = content.content || "";
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @\\}\\)"
// End:

View File

@ -1,10 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
@ -34,10 +28,17 @@
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
// -----------------------------------------------------------------------------
// --SECTION-- number parsers
// --SECTION-- number formatters
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoStructures
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief parses a number
////////////////////////////////////////////////////////////////////////////////
@ -57,8 +58,8 @@ exports.number = function (value, info, lang) {
result = String(value);
}
else {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_NOT_IMPLEMENTED.code;
error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_NOT_IMPLEMENTED;
error.errorMessage = "format '" + format + "' not implemented";
throw error;
@ -69,7 +70,7 @@ exports.number = function (value, info, lang) {
}
return result;
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -1,10 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
@ -34,10 +28,17 @@
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
// -----------------------------------------------------------------------------
// --SECTION-- number parsers
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoStructures
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief parses a number
////////////////////////////////////////////////////////////////////////////////
@ -51,7 +52,7 @@ exports.number = function (value, info, lang) {
format = info.format;
if (format === "%d") {
result = parseInt(value);
result = parseInt(value, 10);
}
else if (format === "%f") {
result = parseFloat(value);
@ -63,8 +64,8 @@ exports.number = function (value, info, lang) {
result = parseInt(value, 8);
}
else {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_NOT_IMPLEMENTED.code;
error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_NOT_IMPLEMENTED;
error.errorMessage = "format '" + format + "' not implemented";
throw error;
@ -75,15 +76,15 @@ exports.number = function (value, info, lang) {
}
if (result === null || result === undefined || isNaN(result)) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_PARSER_FAILED;
error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_PARSER_FAILED;
error.errorMessage = "format '" + format + "' not implemented";
throw error;
}
return result;
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -1,10 +1,4 @@
/*jslint indent: 2,
nomen: true,
maxlen: 100,
sloppy: true,
vars: true,
white: true,
plusplus: true */
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
/*global require, exports */
////////////////////////////////////////////////////////////////////////////////
@ -34,23 +28,30 @@
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("org/arangodb");
// -----------------------------------------------------------------------------
// --SECTION-- number validators
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @addtogroup ArangoStructure
/// @{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @brief positive number
////////////////////////////////////////////////////////////////////////////////
exports.positiveNumber = function (value, info, lang) {
if (value <= 0.0) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_VALIDATION_FAILED.code;
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_VALIDATION_FAILED;
error.errorMessage = "number must be positive";
throw error;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief negative number
@ -58,13 +59,13 @@ exports.positiveNumber = function (value, info, lang) {
exports.negativeNumber = function (value, info, lang) {
if (0.0 <= value) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_VALIDATION_FAILED.code;
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_VALIDATION_FAILED;
error.errorMessage = "number must be negative";
throw error;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief zero
@ -72,13 +73,13 @@ exports.negativeNumber = function (value, info, lang) {
exports.zeroNumber = function (value, info, lang) {
if (value === 0.0) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_VALIDATION_FAILED.code;
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_VALIDATION_FAILED;
error.errorMessage = "number must be zero";
throw error;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief non-positive number
@ -86,13 +87,13 @@ exports.zeroNumber = function (value, info, lang) {
exports.nonPositiveNumber = function (value, info, lang) {
if (0.0 < value) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_VALIDATION_FAILED.code;
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_VALIDATION_FAILED;
error.errorMessage = "number must be non-positive";
throw error;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief non-negative number
@ -100,13 +101,13 @@ exports.nonPositiveNumber = function (value, info, lang) {
exports.nonNegativeNumber = function (value, info, lang) {
if (value < 0.0) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_VALIDATION_FAILED.code;
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_VALIDATION_FAILED;
error.errorMessage = "number must be non-negative";
throw error;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @brief zero
@ -114,13 +115,13 @@ exports.nonNegativeNumber = function (value, info, lang) {
exports.nonZeroNumber = function (value, info, lang) {
if (value !== 0.0) {
error = new ArangoError();
error.errorNum = internal.errors.ERROR_ARANGO_VALIDATION_FAILED.code;
var error = new arangodb.ArangoError();
error.errorNum = arangodb.ERROR_ARANGO_VALIDATION_FAILED;
error.errorMessage = "number must be non-zero";
throw error;
}
}
};
////////////////////////////////////////////////////////////////////////////////
/// @}

View File

@ -5,7 +5,7 @@
vars: true,
white: true,
plusplus: true */
/*global require, db, edges, ModuleCache, Module,
/*global require, db, edges, Module,
ArangoCollection, ArangoDatabase,
ArangoError, ShapedJson,
SYS_DEFINE_ACTION */

View File

@ -92,9 +92,9 @@
}
if (FS_EXISTS(versionFile)) {
if (internal.exists(versionFile)) {
// VERSION file exists, read its contents
var versionInfo = SYS_READ(versionFile);
var versionInfo = internal.read(versionFile);
if (versionInfo != '') {
var versionValues = JSON.parse(versionInfo);
@ -342,13 +342,13 @@
var currentVersion = parseFloat(currentServerVersion[1]);
if (! FS_EXISTS(versionFile)) {
if (! internal.exists(versionFile)) {
console.info("No version information file found in database directory.");
return runUpgrade(currentVersion);
}
// VERSION file exists, read its contents
var versionInfo = SYS_READ(versionFile);
var versionInfo = internal.read(versionFile);
if (versionInfo != '') {
var versionValues = JSON.parse(versionInfo);
if (versionValues && versionValues.version && ! isNaN(versionValues.version)) {

View File

@ -158,6 +158,58 @@ static void InitialiseLockFiles (void) {
Initialised = true;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief lists the directory tree
////////////////////////////////////////////////////////////////////////////////
static void ListTreeRecursively (char const* full,
char const* path,
TRI_vector_string_t* result) {
size_t i;
size_t j;
TRI_vector_string_t dirs = TRI_FilesDirectory(full);
for (j = 0; j < 2; ++j) {
for (i = 0; i < dirs._length; ++i) {
char const* filename = dirs._buffer[i];
char* newfull = TRI_Concatenate2File(full, filename);
char* newpath;
if (*path) {
newpath = TRI_Concatenate2File(path, filename);
}
else {
newpath = TRI_DuplicateString(filename);
}
if (j == 0) {
if (TRI_IsDirectory(newfull)) {
TRI_PushBackVectorString(result, newpath);
if (! TRI_IsSymbolicLink(newfull)) {
ListTreeRecursively(newfull, newpath, result);
}
}
else {
TRI_FreeString(TRI_CORE_MEM_ZONE, newpath);
}
}
else {
if (! TRI_IsDirectory(newfull)) {
TRI_PushBackVectorString(result, newpath);
}
else {
TRI_FreeString(TRI_CORE_MEM_ZONE, newpath);
}
}
TRI_FreeString(TRI_CORE_MEM_ZONE, newfull);
}
}
TRI_DestroyVectorString(&dirs);
}
////////////////////////////////////////////////////////////////////////////////
/// @}
////////////////////////////////////////////////////////////////////////////////
@ -233,6 +285,19 @@ bool TRI_IsDirectory (char const* path) {
return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFDIR);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if path is a symbolic link
////////////////////////////////////////////////////////////////////////////////
bool TRI_IsSymbolicLink (char const* path) {
struct stat stbuf;
int res;
res = lstat(path, &stbuf);
return (res == 0) && ((stbuf.st_mode & S_IFMT) == S_IFLNK);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if file exists
////////////////////////////////////////////////////////////////////////////////
@ -517,6 +582,21 @@ TRI_vector_string_t TRI_FilesDirectory (char const* path) {
#endif
////////////////////////////////////////////////////////////////////////////////
/// @brief lists the directory tree including files and directories
////////////////////////////////////////////////////////////////////////////////
TRI_vector_string_t TRI_FullTreeDirectory (char const* path) {
TRI_vector_string_t result;
TRI_InitVectorString(&result, TRI_CORE_MEM_ZONE);
TRI_PushBackVectorString(&result, TRI_DuplicateString(""));
ListTreeRecursively(path, "", &result);
return result;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief renames a file
////////////////////////////////////////////////////////////////////////////////

View File

@ -69,6 +69,12 @@ int64_t TRI_SizeFile (char const* path);
bool TRI_IsDirectory (char const* path);
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if path is a symbolic link
////////////////////////////////////////////////////////////////////////////////
bool TRI_IsSymbolicLink (char const* path);
////////////////////////////////////////////////////////////////////////////////
/// @brief checks if file exists
////////////////////////////////////////////////////////////////////////////////
@ -123,6 +129,12 @@ char* TRI_Concatenate3File (char const* path1, char const* path2, char const* na
TRI_vector_string_t TRI_FilesDirectory (char const* path);
////////////////////////////////////////////////////////////////////////////////
/// @brief lists the directory tree including files and directories
////////////////////////////////////////////////////////////////////////////////
TRI_vector_string_t TRI_FullTreeDirectory (char const* path);
////////////////////////////////////////////////////////////////////////////////
/// @brief renames a file
////////////////////////////////////////////////////////////////////////////////

View File

@ -223,8 +223,13 @@ bool ClientConnection::read (StringBuffer& stringBuffer) {
int lenRead = ::read(_socket, buffer, READBUFFER_SIZE - 1);
if (lenRead <= 0) {
// error: stop reading
if (lenRead == -1) {
// error occurred
return false;
}
if (lenRead == 0) {
// nothing more to read
break;
}

Some files were not shown because too many files have changed in this diff Show More