mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:triAGENS/ArangoDB into devel
This commit is contained in:
commit
7e8f63add2
|
@ -1,5 +1,186 @@
|
|||
!CHAPTER Collection Methods
|
||||
|
||||
`collection.all()`
|
||||
|
||||
Selects all documents of a collection and returns a cursor. You can use toArray, next, or hasNext to access the result. The result can be limited using the skip and limit operator.
|
||||
|
||||
*Examples*
|
||||
|
||||
Use toArray to get all documents at once:
|
||||
|
||||
arango> db.five.all().toArray();
|
||||
[
|
||||
{ "_id" : "five/1798296", "_key" : "1798296", "_rev" : "1798296", "doc" : 3 },
|
||||
{ "_id" : "five/1732760", "_key" : "1732760", "_rev" : "1732760", "doc" : 2 },
|
||||
{ "_id" : "five/1863832", "_key" : "1863832", "_rev" : "1863832", "doc" : 4 },
|
||||
{ "_id" : "five/1667224", "_key" : "1667224", "_rev" : "1667224", "doc" : 1 },
|
||||
{ "_id" : "five/1929368", "_key" : "1929368", "_rev" : "1929368", "doc" : 5 }
|
||||
]
|
||||
|
||||
Use next to loop over all documents:
|
||||
|
||||
arango> var a = db.five.all();
|
||||
arango> while (a.hasNext()) print(a.next());
|
||||
{ "_id" : "five/1798296", "_key" : "1798296", "_rev" : "1798296", "doc" : 3 }
|
||||
{ "_id" : "five/1732760", "_key" : "1732760", "_rev" : "1732760", "doc" : 2 }
|
||||
{ "_id" : "five/1863832", "_key" : "1863832", "_rev" : "1863832", "doc" : 4 }
|
||||
{ "_id" : "five/1667224", "_key" : "1667224", "_rev" : "1667224", "doc" : 1 }
|
||||
{ "_id" : "five/1929368", "_key" : "1929368", "_rev" : "1929368", "doc" : 5 }
|
||||
|
||||
`collection.byExample( example)`
|
||||
|
||||
Selects all documents of a collection that match the specified example and returns a cursor.
|
||||
|
||||
You can use toArray, next, or hasNext to access the result. The result can be limited using the skip and limit operator.
|
||||
|
||||
An attribute name of the form a.b is interpreted as attribute path, not as attribute. If you use
|
||||
|
||||
{ a : { c : 1 } }
|
||||
|
||||
as example, then you will find all documents, such that the attribute a contains a document of the form {c : 1 }. E.g., the document
|
||||
|
||||
{ a : { c : 1 }, b : 1 }
|
||||
|
||||
will match, but the document
|
||||
|
||||
{ a : { c : 1, b : 1 } }
|
||||
|
||||
will not.
|
||||
|
||||
However, if you use
|
||||
|
||||
{ a.c : 1 },
|
||||
|
||||
then you will find all documents, which contain a sub-document in a that has an attribute c of value 1. E.g., both documents
|
||||
|
||||
{ a : { c : 1 }, b : 1 } and
|
||||
{ a : { c : 1, b : 1 } }
|
||||
|
||||
will match.
|
||||
|
||||
`collection.byExample( path1, value1, ...)`
|
||||
|
||||
As alternative you can supply a list of paths and values.
|
||||
|
||||
*Examples*
|
||||
|
||||
Use toArray to get all documents at once:
|
||||
|
||||
arango> db.users.all().toArray();
|
||||
[ { "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285", "id" : 323, "name" : "Peter" },
|
||||
{ "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749", "id" : 535, "name" : "Peter" },
|
||||
{ "_id" : "users/554833357", "_key" : "554833357", "_rev" : "554833357", "id" : 25, "name" : "Vladimir" } ]
|
||||
|
||||
arango> db.users.byExample({ "id" : 323 }).toArray();
|
||||
[ { "id" : 323, "name" : "Peter", "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285" } ]
|
||||
|
||||
arango> db.users.byExample({ "name" : "Peter" }).toArray();
|
||||
[ { "id" : 323, "name" : "Peter", "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285" },
|
||||
{ "id" : 535, "name" : "Peter", "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749" } ]
|
||||
|
||||
arango> db.users.byExample({ "name" : "Peter", "id" : 535 }).toArray();
|
||||
[ { "id" : 535, "name" : "Peter", "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749" } ]
|
||||
|
||||
Use next to loop over all documents:
|
||||
|
||||
arango> var a = db.users.byExample( {"name" : "Peter" } );
|
||||
arango> while (a.hasNext()) print(a.next());
|
||||
{ "id" : 323, "name" : "Peter", "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285" }
|
||||
{ "id" : 535, "name" : "Peter", "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749" }
|
||||
|
||||
`collection.firstExample( example)`
|
||||
|
||||
Returns the document of a collection that match the specified example or null. The example must be specified as paths and values. See byExample for details.
|
||||
|
||||
`collection.firstExample( path1, value1, ...)`
|
||||
|
||||
As alternative you can supply a list of paths and values.
|
||||
|
||||
*Examples*
|
||||
|
||||
arango> db.users.firstExample("name", 1237);
|
||||
{ "_id" : "users/83049373", "_key" : "83049373", "_rev" : "83049373", "name" : 1237 }
|
||||
|
||||
`collection.range( attribute, left, right)`
|
||||
|
||||
Selects all documents of a collection such that the attribute is greater or equal than left and strictly less than right.
|
||||
|
||||
You can use toArray, next, or hasNext to access the result. The result can be limited using the skip and limit operator.
|
||||
|
||||
An attribute name of the form a.b is interpreted as attribute path, not as attribute.
|
||||
|
||||
For range queries it is required that a skiplist index is present for the queried attribute. If no skiplist index is present on the attribute, an error will be thrown.
|
||||
|
||||
*Examples*
|
||||
|
||||
Use toArray to get all documents at once:
|
||||
|
||||
arangod> l = db.skip.range("age", 10, 13).toArray();
|
||||
[
|
||||
{ "_id" : "skip/4260278", "_key" : "4260278", "_rev" : "4260278", "age" : 10 },
|
||||
{ "_id" : "skip/4325814", "_key" : "4325814", "_rev" : "4325814", "age" : 11 },
|
||||
{ "_id" : "skip/4391350", "_key" : "4391350", "_rev" : "4391350", "age" : 12 }
|
||||
]
|
||||
|
||||
`collection.any()`
|
||||
|
||||
The any method returns a random document from the collection. It returns null if the collection is empty.
|
||||
|
||||
*Examples*
|
||||
|
||||
arangod> db.example.any()
|
||||
{ "_id" : "example/222716379559", "_rev" : "222716379559", "Hello" : "World" }
|
||||
|
||||
`collection.count()`
|
||||
|
||||
Returns the number of living documents in the collection.
|
||||
|
||||
*Examples*
|
||||
|
||||
arango> db.users.count();
|
||||
10001
|
||||
|
||||
`collection.toArray()`
|
||||
|
||||
Converts the collection into an array of documents. Never use this call in a production environment.
|
||||
|
||||
<!--
|
||||
@anchor SimpleQueryAll
|
||||
@copydetails JSF_ArangoCollection_prototype_all
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryByExample
|
||||
@copydetails JSF_ArangoCollection_prototype_byExample
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryFirstExample
|
||||
@copydetails JSF_ArangoCollection_prototype_firstExample
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryAny
|
||||
@copydetails JSF_ArangoCollection_prototype_range
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryRange
|
||||
@copydetails JS_AnyQuery
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryCollectionCount
|
||||
@copydetails JS_CountVocbaseCol
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryToArray
|
||||
@copydetails JSF_ArangoCollection_prototype_toArray
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryFirst
|
||||
@copydetails JSF_ArangoCollection_prototype_first
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryLast
|
||||
@copydetails JSF_ArangoCollection_prototype_last
|
||||
-->
|
||||
|
||||
`collection.document( document)`
|
||||
|
||||
The document method finds a document given its identifier. It returns the document. Note that the returned document contains two pseudo-attributes, namely _id and _rev. _id contains the document-handle and _rev the revision of the document.
|
||||
|
@ -47,16 +228,6 @@ No error will be thrown if the sought document or collection does not exist. Sti
|
|||
|
||||
As before. Instead of document a document-handle can be passed as first argument.
|
||||
|
||||
|
||||
`collection.any()`
|
||||
|
||||
The any method returns a random document from the collection. It returns null if the collection is empty.
|
||||
|
||||
*Examples*
|
||||
|
||||
arangod> db.example.any()
|
||||
{ "_id" : "example/222716379559", "_rev" : "222716379559", "Hello" : "World" }
|
||||
|
||||
`collection.save( data)`
|
||||
|
||||
Creates a new document in the collection from the given data. The data must be a hash array. It must not contain attributes starting with _.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
!CHAPTER What is ArangoDB?
|
||||
!CHAPTER First Steps in ArangoDB
|
||||
|
||||
For installation instructions, please refer to the
|
||||
[Installation Manual](../Installing/README.md).
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
!CHAPTER Iteratively Developing an Application
|
||||
!CHAPTER Developing an Application
|
||||
|
||||
|
||||
While developing a Foxx application, it is recommended to use the development
|
||||
|
@ -10,7 +10,7 @@ recommended to use the development mode in production.
|
|||
During development it is often necessary to log some debug output. ArangoDB
|
||||
provides a few mechanisms for this:
|
||||
|
||||
- using *console.log*:
|
||||
* using *console.log*:
|
||||
ArangoDB provides the *console* module, which you can use from within your
|
||||
Foxx application like this:
|
||||
|
||||
|
@ -21,14 +21,14 @@ provides a few mechanisms for this:
|
|||
ArangoDB's logfile using a *tail -f* command or something similar.
|
||||
Please refer to @ref JSModuleConsole for details.
|
||||
|
||||
- using *internal.print*:
|
||||
* using *internal.print*:
|
||||
The *print* method of the *internal* module writes data to the standard
|
||||
output of the ArangoDB server process. If you have start ArangoDB manually
|
||||
and do not run it as an (unattended) daemon, this is a convenient method:
|
||||
|
||||
require("internal").print(value);
|
||||
|
||||
- tapping requests / responses:
|
||||
* tapping requests / responses:
|
||||
Foxx allows to tap incoming requests and outgoing responses using the *before*
|
||||
and *after* hooks. To print all incoming requests to the stdout of the ArangoDB
|
||||
server process, you could use some code like this in your controller:
|
||||
|
@ -39,3 +39,27 @@ provides a few mechanisms for this:
|
|||
|
||||
Of course you can also use *console.log* or any other means of logging output.
|
||||
|
||||
!SUBSECTION Development Mode
|
||||
|
||||
If you start ArangoDB with the option *--javascript.dev-app-path* followed by
|
||||
the path to a directory containing a manifest file and the path to the
|
||||
database, you are starting ArangoDB in development mode with the application
|
||||
loaded. This means that on every request:
|
||||
|
||||
1. All routes are dropped
|
||||
2. All module caches are flushed
|
||||
3. Your manifest file is read
|
||||
4. All files in your lib folder are loaded
|
||||
5. An app in DIRNAME is mounted at */dev/DIRNAME*
|
||||
6. The request will be processed
|
||||
|
||||
This means that you do not have to restart ArangoDB if you change anything
|
||||
in your app. It is of course not meant for production, because the reloading
|
||||
makes the app relatively slow.
|
||||
|
||||
!SUBSECTION Production Mode
|
||||
|
||||
To run a Foxx app in production first copy your app code to the directory given in
|
||||
the config variable *--javascript.app-path*. After that use Foxx manager to mount the app.
|
||||
You can also use Foxx manager to find out your current app-path.
|
||||
|
||||
|
|
|
@ -512,4 +512,163 @@ Set the content type to JSON and the body to the JSON encoded object you provide
|
|||
|
||||
@copydetails JSF_foxx_BaseMiddleware_response_json
|
||||
|
||||
-->
|
||||
-->
|
||||
|
||||
!SUBSECTION Controlling Access to Foxx Applications
|
||||
|
||||
|
||||
Access to Foxx applications is controlled by the regular authentication mechanisms
|
||||
present in ArangoDB. The server can be run with or without HTTP authentication.
|
||||
|
||||
If authentication is turned on,
|
||||
then every access to the server is authenticated via HTTP authentication. This
|
||||
includes Foxx applications. The global authentication can be toggled
|
||||
via the configuration option @ref CommandLineArangoDisableAuthentication
|
||||
"server.disable-authentication".
|
||||
|
||||
If global HTTP authentication is turned on, requests to Foxx applications will
|
||||
require HTTP authentication too, and only valid users present in the *_users*
|
||||
system collection are allowed to use the applications.
|
||||
|
||||
Since ArangoDB 1.4, there is an extra option to restrict the authentication to
|
||||
just system API calls, such as */_api/...* and */_admin/...*. This option can be
|
||||
turned on using the @ref CommandLineArangoAuthenticateSystemOnly
|
||||
"server.authenticate-system-only" configuration option. If it is turned on,
|
||||
then only system API requests need authentication whereas all requests to Foxx
|
||||
applications and routes will not require authentication.
|
||||
|
||||
This is recommended if you want to disable HTTP authentication for Foxx applications
|
||||
but still want the general database APIs to be protected with HTTP authentication.
|
||||
|
||||
If you need more fine grained control over the access to your Foxx application,
|
||||
we built an authentication system you can use. Currently we only support cookie-based
|
||||
authentication, but we will add the possibility to use Auth Tokens and external OAuth
|
||||
providers in the near future. Of course you can roll your own authentication mechanism
|
||||
if you want to, and you can do it in an application-specific way if required.
|
||||
|
||||
To use the per-application authentication, you should first turn off the global
|
||||
HTTP authentication (or at least restrict it to system API calls as mentioned above).
|
||||
Otherwise clients will need HTTP authentication and need additional authentication by
|
||||
your Foxx application.
|
||||
|
||||
To have global HTTP authentication turned on for system APIs but turned off for Foxx,
|
||||
your server startup parameters should look like this:
|
||||
|
||||
--server.disable-authentication false --server.authenticate-system-only true
|
||||
|
||||
Note: during development, you may even turn off HTTP authentication completely:
|
||||
|
||||
--server.disable-authentication true --server.authenticate-system-only true
|
||||
|
||||
Please keep in mind that turning HTTP authentication off completely will allow
|
||||
unauthenticated access by anyone to all API functions, so do not use this is production.
|
||||
|
||||
Now it's time to configure the application-specific authentication. We built a small
|
||||
[demo application](https://github.com/arangodb/foxx-authentication) to demonstrate how
|
||||
this works.
|
||||
|
||||
To use the application-specific authentication in your own app, first activate it in your controller:
|
||||
|
||||
*FoxxController::activateAuthentication(opts)*
|
||||
|
||||
To activate authentication for this authentication, first call this function. Provide the following arguments:
|
||||
|
||||
type: Currently we only support cookie, but this will change in the future.
|
||||
cookieLifetime: An integer. Lifetime of cookies in seconds.
|
||||
cookieName: A string used as the name of the cookie.
|
||||
sessionLifetime: An integer. Lifetime of sessions in seconds.
|
||||
|
||||
*Examples*
|
||||
|
||||
app.activateAuthentication({
|
||||
type: "cookie",
|
||||
cookieLifetime: 360000,
|
||||
cookieName: "my_cookie",
|
||||
sessionLifetime: 400,
|
||||
});
|
||||
|
||||
!SUBSUBSECTION Adding a login route
|
||||
|
||||
*FoxxController::login(path, opts)*
|
||||
|
||||
Add a route for the login. You can provide further customizations via the the options:
|
||||
|
||||
usernameField and passwordField can be used to adjust the expected attributes in the post request. They default to username and password. onSuccess is a function that you can define to do something if the login was successful. This includes sending a response to the user. This defaults to a function that returns a JSON with user set to the identifier of the user and key set to the session key. onError is a function that you can define to do something if the login did not work. This includes sending a response to the user. This defaults to a function that sets the response to 401 and returns a JSON with error set to "Username or Password was wrong". Both onSuccess and onError should take request and result as arguments.
|
||||
|
||||
*Examples*
|
||||
|
||||
app.login('/login', {
|
||||
onSuccess: function (req, res) {
|
||||
res.json({"success": true});
|
||||
}
|
||||
});
|
||||
|
||||
!SUBSUBSECTION Adding a logout route
|
||||
|
||||
*FoxxController::logout(path, opts)*
|
||||
|
||||
This works pretty similar to the logout function and adds a path to your app for the logout functionality. You can customize it with a custom onSuccess and onError function: onSuccess is a function that you can define to do something if the logout was successful. This includes sending a response to the user. This defaults to a function that returns a JSON with message set to "logged out". onError is a function that you can define to do something if the logout did not work. This includes sending a response to the user. This defaults to a function that sets the response to 401 and returns a JSON with error set to "No session was found". Both onSuccess and onError should take request and result as arguments.
|
||||
|
||||
*Examples*
|
||||
|
||||
app.logout('/logout', {
|
||||
onSuccess: function (req, res) {
|
||||
res.json({"message": "Bye, Bye"});
|
||||
}
|
||||
});
|
||||
|
||||
!SUBSUBSECTION Adding a register route
|
||||
|
||||
*FoxxController::register(path, opts)*
|
||||
|
||||
This works pretty similar to the logout function and adds a path to your app for the register functionality. You can customize it with a custom onSuccess and onError function: onSuccess is a function that you can define to do something if the registration was successful. This includes sending a response to the user. This defaults to a function that returns a JSON with user set to the created user document. onError is a function that you can define to do something if the registration did not work. This includes sending a response to the user. This defaults to a function that sets the response to 401 and returns a JSON with error set to "Registration failed". Both onSuccess and onError should take request and result as arguments. You can also set the fields containing the username and password via usernameField (defaults to username) and passwordField (defaults to password). If you want to accept additional attributes for the user document, use the option acceptedAttributes and set it to an array containing strings with the names of the additional attributes you want to accept. All other attributes in the request will be ignored. If you want default attributes for the accepted attributes or set additional fields (for example admin) use the option defaultAttributes which should be a hash mapping attribute names to default values.
|
||||
|
||||
*Examples*
|
||||
|
||||
app.register('/logout', {
|
||||
acceptedAttributes: ['name'],
|
||||
defaultAttributes: {
|
||||
admin: false
|
||||
}
|
||||
});
|
||||
|
||||
!SUBSUBSECTION Adding a change password route
|
||||
|
||||
*FoxxController::changePassword(route, opts)*
|
||||
|
||||
Add a route for the logged in user to change the password. You can provide further customizations via the the options:
|
||||
|
||||
passwordField can be used to adjust the expected attribute in the post request. It defaults to password. onSuccess is a function that you can define to do something if the change was successful. This includes sending a response to the user. This defaults to a function that returns a JSON with notice set to "Changed password!". onError is a function that you can define to do something if the login did not work. This includes sending a response to the user. This defaults to a function that sets the response to 401 and returns a JSON with error set to "No session was found". Both onSuccess and onError should take request and result as arguments.
|
||||
|
||||
*Examples*
|
||||
|
||||
app.changePassword('/changePassword', {
|
||||
onSuccess: function (req, res) {
|
||||
res.json({"success": true});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
<!--
|
||||
@copydetails JSF_foxx_controller_activateAuthentication
|
||||
|
||||
### Adding a login route
|
||||
|
||||
@copydetails JSF_foxx_controller_login
|
||||
|
||||
### Adding a logout route
|
||||
|
||||
@copydetails JSF_foxx_controller_logout
|
||||
|
||||
### Adding a register route
|
||||
|
||||
@copydetails JSF_foxx_controller_register
|
||||
|
||||
### Adding a change password route
|
||||
|
||||
@copydetails JSF_foxx_controller_changePassword
|
||||
-->
|
||||
|
||||
!SUBSUBSECTION Restricting routes
|
||||
|
||||
To restrict routes, see the documentation for Documenting and Restraining the routes.
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
!CHAPTER The Manifest File
|
||||
|
||||
In the *manifest.json* you define the components of your application.
|
||||
The content is a JSON object with the following attributes (not all
|
||||
attributes are required though):
|
||||
|
||||
* *assets*: Deliver pre-processed files
|
||||
* *author*: The author name
|
||||
* *contributors*: An array containing objects, each represents a contributor (with *name* and optional *email*)
|
||||
* *controllers*: Map routes to FoxxControllers
|
||||
* *defaultDocument*: The default document when the applicated root (*/*) is called (defaults to *index.html*)
|
||||
* *description*: A short description of the application (Meta information)
|
||||
* *engines*: Should be an object with *arangodb* set to the ArangoDB version your Foxx app is compatible with.
|
||||
* *files*: Deliver files
|
||||
* *isSystem*: Mark an application as a system application
|
||||
* *keywords*: An array of keywords to help people find your Foxx app
|
||||
* *lib*: Base path for all required modules
|
||||
* *license*: Short form of the license (MIT, GPL...)
|
||||
* *name*: Name of the application (Meta information)
|
||||
* *repository*: An object with information about where you can find the repository: *type* and *url*
|
||||
* *setup*: Path to a setup script
|
||||
* *teardown*: Path to a teardown script
|
||||
* *thumbnail*: Path to a thumbnail that represents the application (Meta information)
|
||||
* *version*: Current version of the application (Meta information)
|
||||
|
||||
If you install an application using the Foxx manager or are using the
|
||||
development mode, your manifest will be checked for completeness and common errors.
|
||||
You should have a look at the server log files after changing a manifest file to
|
||||
get informed about potential errors in the manifest.
|
||||
|
||||
A more complete example for a Manifest file:
|
||||
|
||||
{
|
||||
"name": "my_website",
|
||||
"version": "1.2.1",
|
||||
"description": "My Website with a blog and a shop",
|
||||
"thumnail": "images/website-logo.png",
|
||||
|
||||
"controllers": {
|
||||
"/blog": "apps/blog.js",
|
||||
"/shop": "apps/shop.js"
|
||||
},
|
||||
|
||||
"lib": "lib",
|
||||
|
||||
"files": {
|
||||
"/images": "images"
|
||||
},
|
||||
|
||||
"assets": {
|
||||
"application.js": {
|
||||
"files": [
|
||||
"vendor/jquery.js",
|
||||
"assets/javascripts/*"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
"setup": "scripts/setup.js",
|
||||
"teardown": "scripts/teardown.js"
|
||||
}
|
||||
|
||||
!SUBSECTION The setup and teardown scripts
|
||||
|
||||
You can provide a path to a JavaScript file that prepares ArangoDB for your
|
||||
application (or respectively removes it entirely). These scripts have access to
|
||||
*appCollection* and *appCollectionName*. Use the *setup* script to create all
|
||||
collections your application needs and fill them with initial data if you want
|
||||
to. Use the *teardown* script to remove all collections you have created.
|
||||
|
||||
Note: the setup script is called on each request in the development mode.
|
||||
If your application needs to set up specific collections, you should always
|
||||
check in the setup script whether they are already there.
|
||||
|
||||
The teardown script is called when an application is uninstalled. It is good
|
||||
practice to drop any collections in the teardown script that the application used
|
||||
exclusively, but this is not enforced. Maybe there are reasons to keep application
|
||||
data even after removing an application. It's up to you to decide what to do.
|
||||
|
||||
!SUBSECTION controllers is an object that matches routes to files
|
||||
|
||||
* The *key* is the route you want to mount at
|
||||
|
||||
* The *value* is the path to the JavaScript file containing the
|
||||
*FoxxController* you want to mount
|
||||
|
||||
You can add multiple controllers in one manifest this way.
|
||||
|
||||
!SUBSECTIONThe files
|
||||
|
||||
Deliver all files in a certain folder without modifying them. You can deliver
|
||||
text files as well as binaries:
|
||||
|
||||
"files": {
|
||||
"/images": "images"
|
||||
}
|
||||
|
||||
!SUBSECTION The assets
|
||||
|
||||
The value for the asset key is an object consisting of paths that are matched
|
||||
to the files they are composed of. Let's take the following example:
|
||||
|
||||
"assets": {
|
||||
"application.js": {
|
||||
"files": [
|
||||
"vendor/jquery.js",
|
||||
"assets/javascripts/*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
If a request is made to */application.js* (in development mode), the file
|
||||
array provided will be processed one element at a time. The elements are
|
||||
paths to files (with the option to use wildcards). The files will be
|
||||
concatenated and delivered as a single file.
|
||||
|
||||
The content-type (or mime type) of the HTTP response when requesting
|
||||
*application.js* is automatically determined by looking at the filename
|
||||
extension in the asset name (*application.js* in the above example).
|
||||
If the asset does not have a filename extension, the content-type is
|
||||
determined by looking at the filename extension of the first file in the
|
||||
*files* list. If no file extension can be determined, the asset will be
|
||||
deliverd with a content-type of *text/plain*.
|
||||
|
||||
It is possible to explicitly override the content-type for an asset by
|
||||
setting the optional *contentType* attribute of an asset as follows:
|
||||
|
||||
"assets": {
|
||||
"myincludes": {
|
||||
"files": [
|
||||
"vendor/jquery.js",
|
||||
"assets/javascripts/*"
|
||||
],
|
||||
"contentType": "text/javascript"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
!CHAPTER Optional Functionality
|
||||
|
||||
!SUBSECTION FormatMiddleware
|
||||
|
||||
To use this plugin, please require it first:
|
||||
|
||||
FormatMiddleware = require("org/arangodb/foxx/template_middleware").FormatMiddleware;
|
||||
|
||||
This Middleware gives you Rails-like format handling via the *extension* of
|
||||
the URL or the accept header. Say you request an URL like */people.json*:
|
||||
|
||||
The *FormatMiddleware* will set the format of the request to JSON and then
|
||||
delete the *.json* from the request. You can therefore write handlers that
|
||||
do not take an *extension* into consideration and instead handle the
|
||||
format via a simple string. To determine the format of the request it
|
||||
checks the URL and then the *accept* header. If one of them gives a format
|
||||
or both give the same, the format is set. If the formats are not the same,
|
||||
an error is raised.
|
||||
|
||||
Use it by calling:
|
||||
|
||||
FormatMiddleware = require('foxx').FormatMiddleware;
|
||||
app.before(FormatMiddleware.new(['json']));
|
||||
|
||||
In both forms you can give a default format as a second parameter, if no
|
||||
format could be determined. If you give no *defaultFormat* this case will be
|
||||
handled as an error.
|
||||
|
||||
!SUBSECTION TemplateMiddleware
|
||||
|
||||
To use this plugin, please require it first:
|
||||
|
||||
TemplateMiddleware = require("org/arangodb/foxx/template_middleware").TemplateMiddleware;
|
||||
|
||||
The *TemplateMiddleware* can be used to give a Foxx.Controller the capability
|
||||
of using templates. Currently you can only use Underscore Templates. It
|
||||
expects documents in the following form in this collection:
|
||||
|
||||
{
|
||||
path: "high/way",
|
||||
content: "hello <%= username %>",
|
||||
contentType: "text/plain",
|
||||
templateLanguage: "underscore"
|
||||
}
|
||||
|
||||
The *content* is the string that will be rendered by the template processor.
|
||||
The *contentType* is the type of content that results from this call. And with
|
||||
the *templateLanguage* you can choose your template processor. There is only
|
||||
one choice now: *underscore*. Which would set the body of the response to
|
||||
*hello Controller* with the template defined above. It will also set the
|
||||
*contentType* to *text/plain* in this case. In addition to the attributes
|
||||
you provided, you also have access to all your view helpers.
|
||||
|
||||
!SUBSUBSECTION Initialize
|
||||
|
||||
Initialize with the name of a collection or a collection and optionally a set of helper functions. Then use before to attach the initialized middleware to your Foxx.Controller
|
||||
|
||||
*Examples*
|
||||
|
||||
templateMiddleware = new TemplateMiddleware("templates", {
|
||||
uppercase: function (x) { return x.toUpperCase(); }
|
||||
});
|
||||
// or without helpers:
|
||||
//templateMiddleware = new TemplateMiddleware("templates");
|
||||
app.before(templateMiddleware);
|
||||
|
||||
!SUBSUBSECTION Render
|
||||
|
||||
`response.render(templatePath, data)`
|
||||
|
||||
When the TemplateMiddleware is included, you will have access to the render function on the response object. If you call render, Controller will look into the this collection and search by the path attribute. It will then render the template with the given data.
|
||||
|
||||
*Examples*
|
||||
|
||||
response.render("high/way", {username: 'Application'})
|
||||
|
||||
<!--
|
||||
### Initialize
|
||||
|
||||
@copydetails JSF_foxx_TemplateMiddleware_initializer
|
||||
|
||||
### Render
|
||||
|
||||
@copydetails JSF_foxx_TemplateMiddleware_response_render
|
||||
-->
|
|
@ -146,6 +146,7 @@ attributes are required though):
|
|||
* *license*: Short form of the license (MIT, GPL...)
|
||||
* *name*: Name of the application (Meta information)
|
||||
* *repository*: An object with information about where you can find the repository: *type* and *url*
|
||||
* *rootElement*: Do you want to have a root element in the requests bodies? Default is false.
|
||||
* *setup*: Path to a setup script
|
||||
* *teardown*: Path to a teardown script
|
||||
* *thumbnail*: Path to a thumbnail that represents the application (Meta information)
|
||||
|
@ -528,4 +529,4 @@ When the TemplateMiddleware is included, you will have access to the render func
|
|||
### Render
|
||||
|
||||
@copydetails JSF_foxx_TemplateMiddleware_response_render
|
||||
-->
|
||||
-->
|
||||
|
|
|
@ -78,7 +78,23 @@ alternative call:
|
|||
_key: "123"
|
||||
};
|
||||
```
|
||||
!SUBSECTION Orphan Collections
|
||||
|
||||
Each graph has an orphan collection. It consists of arbitrary many vertex collection (type *document*), that are not
|
||||
used in an edge definition of the graph. If the graph is extended with an edge definition, which is part of the orphan
|
||||
collection, it will be removed from the orphan collection automatically.
|
||||
|
||||
!SUBSUBSECTION Add
|
||||
|
||||
<!-- @startDocuBlock JSF_general_graph__addOrphanCollection -->
|
||||
|
||||
!SUBSUBSECTION Read
|
||||
|
||||
<!-- @startDocuBlock JSF_general_graph__getOrphanCollections -->
|
||||
|
||||
!SUBSUBSECTION Remove
|
||||
|
||||
<!-- @startDocuBlock JSF_general_graph__removeOrphanCollection -->
|
||||
|
||||
!SUBSECTION Read a graph
|
||||
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
!CHAPTER BitArray Indexes
|
||||
|
||||
!SUBSECTION Introduction to Bit-Array Indexes
|
||||
|
||||
It is possible to define a bit-array index on one or more attributes (or paths)
|
||||
of a documents.
|
||||
|
||||
!SUBSECTION Accessing BitArray Indexes from the Shell
|
||||
|
||||
`collection.ensureBitarray( field1, value1, ..., fieldn, valuen)`
|
||||
|
||||
Creates a bitarray index on documents using attributes as paths to the fields ( field1,..., fieldn). A value ( value1,..., valuen) consists of an array of possible values that the field can take. At least one field and one set of possible values must be given.
|
||||
|
||||
All documents, which do not have all of the attribute paths are ignored (that is, are not part of the bitarray index, they are however stored within the collection). A document which contains all of the attribute paths yet has one or more values which are not part of the defined range of values will be rejected and the document will not inserted within the collection. Note that, if a bitarray index is created subsequent to any documents inserted in the given collection, then the creation of the index will fail if one or more documents are rejected (due to attribute values being outside the designated range).
|
||||
|
||||
In case that the index was successfully created, the index identifier is returned.
|
||||
|
||||
In the example below we create a bitarray index with one field and that field can have the values of either 0 or 1. Any document which has the attribute x defined and does not have a value of 0 or 1 will be rejected and therefore not inserted within the collection. Documents without the attribute x defined will not take part in the index.
|
||||
|
||||
arango> arangod> db.example.ensureBitarray("x", [0,1]);
|
||||
{
|
||||
"id" : "2755894/3607862",
|
||||
"unique" : false,
|
||||
"type" : "bitarray",
|
||||
"fields" : [["x", [0, 1]]],
|
||||
"undefined" : false,
|
||||
"isNewlyCreated" : true
|
||||
}
|
||||
|
||||
In the example below we create a bitarray index with one field and that field can have the values of either 0, 1 or other (indicated by []). Any document which has the attribute x defined will take part in the index. Documents without the attribute x defined will not take part in the index.
|
||||
|
||||
arangod> db.example.ensureBitarray("x", [0,1,[]]);
|
||||
{
|
||||
"id" : "2755894/4263222",
|
||||
"unique" : false,
|
||||
"type" : "bitarray",
|
||||
"fields" : [["x", [0, 1, [ ]]]],
|
||||
"undefined" : false,
|
||||
"isNewlyCreated" : true
|
||||
}
|
||||
|
||||
In the example below we create a bitarray index with two fields. Field x can have the values of either 0 or 1; while field y can have the values of 2 or "a". A document which does not have both attributes x and y will not take part within the index. A document which does have both attributes x and y defined must have the values 0 or 1 for attribute x and 2 or a for attribute y, otherwise the document will not be inserted within the collection.
|
||||
|
||||
arangod> db.example.ensureBitarray("x", [0,1], "y", [2,"a"]);
|
||||
{
|
||||
"id" : "2755894/5246262",
|
||||
"unique" : false,
|
||||
"type" : "bitarray",
|
||||
"fields" : [["x", [0, 1]], ["y", [0, 1]]],
|
||||
"undefined" : false,
|
||||
"isNewlyCreated" : false
|
||||
}
|
||||
|
||||
In the example below we create a bitarray index with two fields. Field x can have the values of either 0 or 1; while field y can have the values of 2, "a" or other . A document which does not have both attributes x and y will not take part within the index. A document which does have both attributes x and y defined must have the values 0 or 1 for attribute x and any value for attribute y will be acceptable, otherwise the document will not be inserted within the collection.
|
||||
|
||||
arangod> db.example.ensureBitarray("x", [0,1], "y", [2,"a",[]]);
|
||||
{
|
||||
"id" : "2755894/5770550",
|
||||
"unique" : false,
|
||||
"type" : "bitarray",
|
||||
"fields" : [["x", [0, 1]], ["y", [2, "a", [ ]]]],
|
||||
"undefined" : false,
|
||||
"isNewlyCreated" : true
|
||||
}
|
||||
|
||||
<!--
|
||||
@anchor IndexBitArrayShellEnsureBitarray
|
||||
@copydetails JSF_ArangoCollection_prototype_ensureBitarray
|
||||
-->
|
|
@ -1,7 +1,9 @@
|
|||
!CHAPTER Installing
|
||||
|
||||
This chapter describes how to install ArangoDB under various operation
|
||||
systems.
|
||||
This chapter describes how to install ArangoDB under various operation systems.
|
||||
|
||||
First of all download and install the corresponding RPM or Debian package or use homebrew on the MacOS X.
|
||||
You can find packages for various operation systems at our [download](http://www.arangodb.org/download) section.
|
||||
|
||||
If you don't want to install ArangoDB at the beginning and just want to experiment with the features, you can use our [online demo](https://www.arangodb.org/tryitout).
|
||||
|
||||
|
|
|
@ -1,182 +0,0 @@
|
|||
!CHAPTER QUERIES
|
||||
|
||||
`all()`
|
||||
|
||||
Selects all documents of a collection and returns a cursor. You can use toArray, next, or hasNext to access the result. The result can be limited using the skip and limit operator.
|
||||
|
||||
*Examples*
|
||||
|
||||
Use toArray to get all documents at once:
|
||||
|
||||
arango> db.five.all().toArray();
|
||||
[
|
||||
{ "_id" : "five/1798296", "_key" : "1798296", "_rev" : "1798296", "doc" : 3 },
|
||||
{ "_id" : "five/1732760", "_key" : "1732760", "_rev" : "1732760", "doc" : 2 },
|
||||
{ "_id" : "five/1863832", "_key" : "1863832", "_rev" : "1863832", "doc" : 4 },
|
||||
{ "_id" : "five/1667224", "_key" : "1667224", "_rev" : "1667224", "doc" : 1 },
|
||||
{ "_id" : "five/1929368", "_key" : "1929368", "_rev" : "1929368", "doc" : 5 }
|
||||
]
|
||||
|
||||
Use next to loop over all documents:
|
||||
|
||||
arango> var a = db.five.all();
|
||||
arango> while (a.hasNext()) print(a.next());
|
||||
{ "_id" : "five/1798296", "_key" : "1798296", "_rev" : "1798296", "doc" : 3 }
|
||||
{ "_id" : "five/1732760", "_key" : "1732760", "_rev" : "1732760", "doc" : 2 }
|
||||
{ "_id" : "five/1863832", "_key" : "1863832", "_rev" : "1863832", "doc" : 4 }
|
||||
{ "_id" : "five/1667224", "_key" : "1667224", "_rev" : "1667224", "doc" : 1 }
|
||||
{ "_id" : "five/1929368", "_key" : "1929368", "_rev" : "1929368", "doc" : 5 }
|
||||
|
||||
`collection.byExample( example)`
|
||||
|
||||
Selects all documents of a collection that match the specified example and returns a cursor.
|
||||
|
||||
You can use toArray, next, or hasNext to access the result. The result can be limited using the skip and limit operator.
|
||||
|
||||
An attribute name of the form a.b is interpreted as attribute path, not as attribute. If you use
|
||||
|
||||
{ a : { c : 1 } }
|
||||
|
||||
as example, then you will find all documents, such that the attribute a contains a document of the form {c : 1 }. E.g., the document
|
||||
|
||||
{ a : { c : 1 }, b : 1 }
|
||||
|
||||
will match, but the document
|
||||
|
||||
{ a : { c : 1, b : 1 } }
|
||||
|
||||
will not.
|
||||
|
||||
However, if you use
|
||||
|
||||
{ a.c : 1 },
|
||||
|
||||
then you will find all documents, which contain a sub-document in a that has an attribute c of value 1. E.g., both documents
|
||||
|
||||
{ a : { c : 1 }, b : 1 } and
|
||||
{ a : { c : 1, b : 1 } }
|
||||
|
||||
will match.
|
||||
|
||||
`collection.byExample( path1, value1, ...)`
|
||||
|
||||
As alternative you can supply a list of paths and values.
|
||||
|
||||
*Examples*
|
||||
|
||||
Use toArray to get all documents at once:
|
||||
|
||||
arango> db.users.all().toArray();
|
||||
[ { "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285", "id" : 323, "name" : "Peter" },
|
||||
{ "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749", "id" : 535, "name" : "Peter" },
|
||||
{ "_id" : "users/554833357", "_key" : "554833357", "_rev" : "554833357", "id" : 25, "name" : "Vladimir" } ]
|
||||
|
||||
arango> db.users.byExample({ "id" : 323 }).toArray();
|
||||
[ { "id" : 323, "name" : "Peter", "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285" } ]
|
||||
|
||||
arango> db.users.byExample({ "name" : "Peter" }).toArray();
|
||||
[ { "id" : 323, "name" : "Peter", "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285" },
|
||||
{ "id" : 535, "name" : "Peter", "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749" } ]
|
||||
|
||||
arango> db.users.byExample({ "name" : "Peter", "id" : 535 }).toArray();
|
||||
[ { "id" : 535, "name" : "Peter", "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749" } ]
|
||||
|
||||
Use next to loop over all documents:
|
||||
|
||||
arango> var a = db.users.byExample( {"name" : "Peter" } );
|
||||
arango> while (a.hasNext()) print(a.next());
|
||||
{ "id" : 323, "name" : "Peter", "_id" : "users/554702285", "_key" : "554702285", "_rev" : "554702285" }
|
||||
{ "id" : 535, "name" : "Peter", "_id" : "users/554636749", "_key" : "554636749", "_rev" : "554636749" }
|
||||
|
||||
`collection.firstExample( example)`
|
||||
|
||||
Returns the a document of a collection that match the specified example or null. The example must be specified as paths and values. See byExample for details.
|
||||
|
||||
`collection.firstExample( path1, value1, ...)`
|
||||
|
||||
As alternative you can supply a list of paths and values.
|
||||
|
||||
*Examples*
|
||||
|
||||
arango> db.users.firstExample("name", 1237);
|
||||
{ "_id" : "users/83049373", "_key" : "83049373", "_rev" : "83049373", "name" : 1237 }
|
||||
|
||||
`collection.range( attribute, left, right)`
|
||||
|
||||
Selects all documents of a collection such that the attribute is greater or equal than left and strictly less than right.
|
||||
|
||||
You can use toArray, next, or hasNext to access the result. The result can be limited using the skip and limit operator.
|
||||
|
||||
An attribute name of the form a.b is interpreted as attribute path, not as attribute.
|
||||
|
||||
For range queries it is required that a skiplist index is present for the queried attribute. If no skiplist index is present on the attribute, an error will be thrown.
|
||||
|
||||
*Examples*
|
||||
|
||||
Use toArray to get all documents at once:
|
||||
|
||||
arangod> l = db.skip.range("age", 10, 13).toArray();
|
||||
[
|
||||
{ "_id" : "skip/4260278", "_key" : "4260278", "_rev" : "4260278", "age" : 10 },
|
||||
{ "_id" : "skip/4325814", "_key" : "4325814", "_rev" : "4325814", "age" : 11 },
|
||||
{ "_id" : "skip/4391350", "_key" : "4391350", "_rev" : "4391350", "age" : 12 }
|
||||
]
|
||||
|
||||
`collection.any()`
|
||||
|
||||
The any method returns a random document from the collection. It returns null if the collection is empty.
|
||||
|
||||
*Examples*
|
||||
|
||||
arangod> db.example.any()
|
||||
{ "_id" : "example/222716379559", "_rev" : "222716379559", "Hello" : "World" }
|
||||
|
||||
`collection.count()`
|
||||
|
||||
Returns the number of living documents in the collection.
|
||||
|
||||
*Examples*
|
||||
|
||||
arango> db.users.count();
|
||||
10001
|
||||
|
||||
`collection.toArray()`
|
||||
|
||||
Converts the collection into an array of documents. Never use this call in a production environment.
|
||||
|
||||
<!--
|
||||
@anchor SimpleQueryAll
|
||||
@copydetails JSF_ArangoCollection_prototype_all
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryByExample
|
||||
@copydetails JSF_ArangoCollection_prototype_byExample
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryFirstExample
|
||||
@copydetails JSF_ArangoCollection_prototype_firstExample
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryAny
|
||||
@copydetails JSF_ArangoCollection_prototype_range
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryRange
|
||||
@copydetails JS_AnyQuery
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryCollectionCount
|
||||
@copydetails JS_CountVocbaseCol
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryToArray
|
||||
@copydetails JSF_ArangoCollection_prototype_toArray
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryFirst
|
||||
@copydetails JSF_ArangoCollection_prototype_first
|
||||
|
||||
@CLEARPAGE
|
||||
@anchor SimpleQueryLast
|
||||
@copydetails JSF_ArangoCollection_prototype_last
|
||||
-->
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,3 @@
|
|||
@import "vendors/bootstrap/bootstrap.less";
|
||||
@import "mixins.less";
|
||||
|
||||
@import "ebook/variables.less";
|
||||
|
@ -12,16 +11,11 @@ article {
|
|||
page-break-after: always;
|
||||
}
|
||||
|
||||
h1 { font-size: floor(@font-size-base * 2.15); }
|
||||
h2 { font-size: floor(@font-size-base * 1.70); }
|
||||
h3 { font-size: ceil(@font-size-base * 1.25); }
|
||||
h4 { font-size: ceil(@font-size-base * 1); }
|
||||
h5 { font-size: ceil(@font-size-base * 0.85); }
|
||||
h6 { font-size: ceil(@font-size-base * 0.65); }
|
||||
|
||||
pre, blockquote {
|
||||
border: 1px solid #999;
|
||||
page-break-inside: avoid;
|
||||
background: #f1f1f1;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -30,7 +24,7 @@ img {
|
|||
margin: 0px auto;
|
||||
}
|
||||
|
||||
.exercise {
|
||||
.exercise, .quiz {
|
||||
margin: 1cm 0cm;
|
||||
padding: 0.4cm;
|
||||
page-break-inside: avoid;
|
||||
|
@ -42,4 +36,8 @@ img {
|
|||
padding-bottom: 0.2cm;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.question {
|
||||
margin-top: 0.4cm;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,8 @@
|
|||
|
||||
background: @page-background;
|
||||
border-radius: 2px;
|
||||
line-height: 1.5em;
|
||||
line-height: @content-line-height;
|
||||
font-size: @default-font-size;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
|
|
|
@ -301,7 +301,7 @@
|
|||
font-size: inherit;
|
||||
line-height: 1.5em;
|
||||
overflow: auto;
|
||||
padding: 20px;
|
||||
padding: 10px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
flex-direction: column;
|
||||
|
||||
font-size: 40px;
|
||||
color: rgba(0,0,0,0.4);
|
||||
color: rgba(0, 0, 0, 0.2);
|
||||
|
||||
text-align: center;
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
|||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: rgba(0,0,0,0.6);
|
||||
color: rgba(0, 0, 0, 0.6);
|
||||
}
|
||||
|
||||
&.navigation-next {
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
@page-color: black;
|
||||
@page-background: @body-background;
|
||||
|
||||
// Content
|
||||
@content-line-height: 1.6em;
|
||||
|
||||
// Progress Bar
|
||||
@chapter-display: none;
|
||||
@chapter-size: 16px;
|
||||
|
@ -86,11 +89,12 @@
|
|||
@FontPath: '@{staticPath}/fonts';
|
||||
@fa-font-path: "@{FontPath}/fontawesome";
|
||||
|
||||
@s-font-size: 1.2rem;
|
||||
@m-font-size: 1.4rem;
|
||||
@l-font-size: 1.6rem;
|
||||
@s-font-size: 1.2rem;
|
||||
@m-font-size: 1.4rem;
|
||||
@l-font-size: 1.6rem;
|
||||
@xl-font-size: 2.2rem;
|
||||
@xxl-font-size: 4.0rem;
|
||||
@default-font-size: @l-font-size;
|
||||
|
||||
/*
|
||||
,--------.,--.
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
{% if options.links.sharing.twitter !== false %}
|
||||
<a href="#" target="_blank" class="btn pull-right twitter-sharing-link sharing-link" data-sharing="twitter" aria-label="Share on Twitter"><i class="fa fa-twitter"></i></a>
|
||||
{% endif %}
|
||||
|
||||
{% if githubId %}
|
||||
<a href="{{ githubHost }}{{ githubId }}/stargazers" target="_blank" class="btn pull-right count-star hidden-xs"><i class="fa fa-star-o"></i> Star (<span>-</span>)</a>
|
||||
<a href="{{ githubHost }}{{ githubId }}/watchers" target="_blank" class="btn pull-right count-watch hidden-xs"><i class="fa fa-eye"></i> Watch (<span>-</span>)</a>
|
||||
|
@ -23,8 +22,7 @@
|
|||
|
||||
<!-- Title -->
|
||||
<h1>
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
<a href="https://www.arangodb.org" > <img src="../Arangodb_Logo.png" alt="ArangoDB" border="0" style="position:relative"></a>
|
||||
<div style="position:relative; bottom:45px; left:90px; font-size:12pt">2.1.0</div>
|
||||
<a href="https://www.arangodb.org" > <img src="../Arangodb_Logo.png" alt="ArangoDB" style="position:relative; border:0px; top:-4px"></a>
|
||||
<div style="position:relative; bottom:50px; left:79px; font-size:12pt">2.1.0</div>
|
||||
</h1>
|
||||
</div>
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
<input type="text" placeholder="Search" class="form-control" />
|
||||
</div>
|
||||
<ul class="summary">
|
||||
{% set _divider = false %}
|
||||
{% if options.links.issues !== false && (options.links.issues || githubId) %}
|
||||
{% set _divider = true %}
|
||||
<li>
|
||||
|
@ -36,15 +37,9 @@
|
|||
<a href="{{ basePath }}/"><i class="fa fa-check"></i> Introduction</a>
|
||||
</li>
|
||||
{{ articles(summary.chapters) }}
|
||||
|
||||
{% if options.links.gitbook !== false %}
|
||||
<li class="divider"></li>
|
||||
<li>
|
||||
<a href="http://www.gitbook.io/" target="blank" class="gitbook-link">Generated using GitBook</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
</ul>
|
||||
</div>
|
||||
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
jQuery(".summary>li").each(function(){
|
||||
var flag = true;
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="{{ staticBase }}/style.css">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="book-langs-index">
|
||||
<div class="inner">
|
||||
|
|
|
@ -1,54 +1,26 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en-US" {% block htmlTag %}{% endblock %}>
|
||||
{{ htmlSnippet("html:start")|default("") }}
|
||||
<head prefix="og: http://ogp.me/ns# book: http://ogp.me/ns/book#">
|
||||
<head>
|
||||
{{ htmlSnippet("head:start")|default("") }}
|
||||
{% block head %}
|
||||
<meta charset="UTF-8">
|
||||
<title>{% block title %} | {{ title }}{% endblock %}</title>
|
||||
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
|
||||
<meta name="robots" content="index, follow">
|
||||
<meta name="author" content="{{ githubAuthor }}">
|
||||
<meta name="description" content="{{ description }}">
|
||||
<meta name="keywords" content="gitbook,github" >
|
||||
<meta name="generator" content="www.gitbook.io">
|
||||
|
||||
{% if progress.current.next and progress.current.next.path %}
|
||||
<link rel="next" href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" />
|
||||
{% endif %}
|
||||
{% if progress.current.prev and progress.current.prev.path %}
|
||||
<link rel="prev" href="{{ basePath }}/{{ progress.current.prev.path|mdLink }}" />
|
||||
{% endif %}
|
||||
|
||||
<meta property="og:title" content="{% block title %} | {{ title }}{% endblock %}">
|
||||
<meta property="og:site_name" content="{{ title }}">
|
||||
<meta property="og:type" content="book">
|
||||
<meta property="og:locale" content="en_US">
|
||||
|
||||
<meta property="book:author" content="{{ githubHost }}{{ githubAuthor }}">
|
||||
<meta property="book:tag" content="GitBook">
|
||||
|
||||
<meta name="description" content="{% block description %}{% endblock %}">
|
||||
<meta name="generator" content="GitBook {{ gitbook.version }}">
|
||||
<meta name="HandheldFriendly" content="true"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
||||
|
||||
<link rel="shortcut icon" href="{{ staticBase }}/images/favicon.ico" type="image/x-icon">
|
||||
{% endblock %}
|
||||
{% block head %}{% endblock %}
|
||||
{{ htmlSnippet("head:end")|default("") }}
|
||||
</head>
|
||||
<body>
|
||||
{{ htmlSnippet("body:start")|default("") }}
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="{{ staticBase }}/style.css">
|
||||
{% endblock %}
|
||||
{% block style %}{% endblock %}
|
||||
{% block content %}{% endblock %}
|
||||
{% block javascript %}
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/ace.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.3/mode-javascript.js"></script>
|
||||
<script src="{{ staticBase }}/jsrepl/jsrepl.js" id="jsrepl-script"></script>
|
||||
<script src="{{ staticBase }}/app.js"></script>
|
||||
{% endblock %}
|
||||
{% block javascript %}{% endblock %}
|
||||
{{ htmlSnippet("body:end")|default("") }}
|
||||
</body>
|
||||
{{ htmlSnippet("html:end")|default("") }}
|
||||
|
|
|
@ -20,9 +20,14 @@
|
|||
</div>
|
||||
{% elif section.type == "quiz" %}
|
||||
<div class="quiz">
|
||||
<div class="exercise-header">Exercise #{{ exercise }}</div>
|
||||
<div class="exercise-header">Quiz #{{ exercise }}</div>
|
||||
{% autoescape false %}{{ section.content }}{% endautoescape %}
|
||||
{% autoescape false %}{{ section.quiz.base }}{% endautoescape %}
|
||||
{% for quiz in section.quiz %}
|
||||
<div class="question">
|
||||
<div class="question-header">Question {{ loop.index }} of {{ section.quiz.length }}</div>
|
||||
{% autoescape false %}{{ quiz.base }}{% endautoescape %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% set exercise = exercise + 1 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
@ -60,9 +65,14 @@
|
|||
</div>
|
||||
{% elif section.type == "quiz" %}
|
||||
<div class="quiz">
|
||||
<div class="exercise-header">Exercise #{{ exercise }}</div>
|
||||
<div class="exercise-header">Quiz #{{ exercise }}</div>
|
||||
{% autoescape false %}{{ section.content }}{% endautoescape %}
|
||||
{% autoescape false %}{{ section.quiz.solution }}{% endautoescape %}
|
||||
{% for quiz in section.quiz %}
|
||||
<div class="question">
|
||||
<div class="question-header">Question {{ loop.index }} of {{ section.quiz.length }}</div>
|
||||
{% autoescape false %}{{ quiz.solution }}{% endautoescape %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% set exercise = exercise + 1 %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -1,7 +1,23 @@
|
|||
{% extends "layout.html" %}
|
||||
|
||||
{% block htmlTag %}{% if options.cache !== false %}manifest="{{ basePath }}/manifest.appcache"{% endif %}{% endblock %}
|
||||
{% block title %}{{ progress.current.title }}{% parent %}{% endblock %}
|
||||
|
||||
{% block head %}
|
||||
{% parent %}
|
||||
{% if githubAuthor %}
|
||||
<meta name="author" content="{{ githubAuthor }}">
|
||||
{% endif %}
|
||||
{% if progress.current.next and progress.current.next.path %}
|
||||
<link rel="next" href="{{ basePath }}/{{ progress.current.next.path|mdLink }}" />
|
||||
{% endif %}
|
||||
{% if progress.current.prev and progress.current.prev.path %}
|
||||
<link rel="prev" href="{{ basePath }}/{{ progress.current.prev.path|mdLink }}" />
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}{{ progress.current.title }} | {{ title }}{% endblock %}
|
||||
{% block description %}{% if progress.current.level == "0" %}{{ description }}{% endif %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="book" {% if githubId %}data-github="{{ githubId }}"{% endif %} data-level="{{ progress.current.level }}" data-basepath="{{ basePath }}" data-revision="{{ revision }}">
|
||||
{% include "includes/book/header.html" %}
|
||||
|
@ -38,7 +54,8 @@
|
|||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
{% parent %}
|
||||
<script src="{{ staticBase }}/jsrepl/jsrepl.js" id="jsrepl-script"></script>
|
||||
<script src="{{ staticBase }}/app.js"></script>
|
||||
{% for resource in plugins.resources.js %}
|
||||
{% if resource.url %}
|
||||
<script src="{{ resource.url }}"></script>
|
||||
|
@ -55,7 +72,7 @@ require(["gitbook"], function(gitbook) {
|
|||
{% endblock %}
|
||||
|
||||
{% block style %}
|
||||
{% parent %}
|
||||
<link rel="stylesheet" href="{{ staticBase }}/style.css">
|
||||
{% for resource in plugins.resources.css %}
|
||||
{% if resource.url %}
|
||||
<link rel="stylesheet" href="{{ resource.url }}">
|
||||
|
|
|
@ -15,7 +15,9 @@ JAVASCRIPT_BROWSER = \
|
|||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-query-cursor.js \
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arango-statement.js \
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/arangosh.js \
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/general-graph.js \
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph.js \
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/graph-blueprint.js \
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb/simple-query.js \
|
||||
\
|
||||
js/apps/system/aardvark/frontend/js/modules/org/arangodb-common.js \
|
||||
|
@ -31,6 +33,7 @@ JAVASCRIPT_BROWSER = \
|
|||
js/apps/system/aardvark/frontend/js/bootstrap/errors.js \
|
||||
js/apps/system/aardvark/frontend/js/bootstrap/monkeypatches.js \
|
||||
js/apps/system/aardvark/frontend/js/bootstrap/module-internal.js \
|
||||
js/apps/system/aardvark/frontend/js/bootstrap/module-console.js \
|
||||
\
|
||||
js/apps/system/aardvark/frontend/js/client/client.js \
|
||||
js/apps/system/aardvark/frontend/js/client/bootstrap/module-internal.js
|
||||
|
|
|
@ -215,6 +215,7 @@
|
|||
"ERROR_GRAPH_DUPLICATE" : { "code" : 1925, "message" : "graph already exists" },
|
||||
"ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST" : { "code" : 1926, "message" : "collection does not exist" },
|
||||
"ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX" : { "code" : 1927, "message" : "not a vertex collection" },
|
||||
"ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION" : { "code" : 1928, "message" : "not in orphan collection" },
|
||||
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
|
||||
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
|
||||
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
|
||||
|
|
|
@ -0,0 +1,431 @@
|
|||
/*jslint indent: 2, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, sloppy: true */
|
||||
/*global require, SYS_GETLINE, SYS_LOG, jqconsole */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief module "console"
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2004-2013 triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler
|
||||
/// @author Copyright 2010-2013, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
(function () {
|
||||
// cannot use strict here as we are going to delete globals
|
||||
|
||||
var exports = require("console");
|
||||
|
||||
var sprintf = require("internal").sprintf;
|
||||
var inspect = require("internal").inspect;
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Module "console"
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private variables
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief group level
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var groupLevel = "";
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief timers
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var timers = { };
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- private functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief internal logging
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var log;
|
||||
|
||||
try {
|
||||
// this will work when we are in arangod but not in the browser / web interface
|
||||
log = SYS_LOG;
|
||||
delete SYS_LOG;
|
||||
}
|
||||
catch (err) {
|
||||
// this will work in the web interface
|
||||
log = function (level, message) {
|
||||
if (jqconsole) {
|
||||
jqconsole.Write(message + "\n", 'jssuccess');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief internal logging with group level
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function logGroup (level, msg) {
|
||||
'use strict';
|
||||
|
||||
log(level, groupLevel + msg);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public functions
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief assert
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.assert = function (condition) {
|
||||
'use strict';
|
||||
|
||||
if (condition) {
|
||||
return;
|
||||
}
|
||||
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, args);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + args;
|
||||
}
|
||||
|
||||
logGroup("error", msg);
|
||||
|
||||
require('assert').ok(condition, msg);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief debug
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.debug = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
logGroup("debug", msg);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief debugLines
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.debugLines = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
var a = msg.split("\n");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < a.length; ++i) {
|
||||
logGroup("debug", a[i]);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief dir
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.dir = function (object) {
|
||||
'use strict';
|
||||
|
||||
logGroup("info", inspect(object));
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief error
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.error = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
logGroup("error", msg);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief errorLines
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.errorLines = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
var a = msg.split("\n");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < a.length; ++i) {
|
||||
logGroup("error", a[i]);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief getline
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
if (typeof SYS_GETLINE !== "undefined") {
|
||||
exports.getline = SYS_GETLINE;
|
||||
delete SYS_GETLINE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief group
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.group = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
groupLevel = groupLevel + " ";
|
||||
logGroup("info", msg);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief groupCollapsed
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.groupCollapsed = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
logGroup("info", msg);
|
||||
groupLevel = groupLevel + " ";
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief groupEnd
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.groupEnd = function () {
|
||||
'use strict';
|
||||
|
||||
groupLevel = groupLevel.substr(2);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief info
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.info = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
logGroup("info", msg);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief infoLines
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.infoLines = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
var a = msg.split("\n");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < a.length; ++i) {
|
||||
logGroup("info", a[i]);
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief log
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.log = exports.info;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief logLines
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.logLines = exports.infoLines;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief time
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.time = function (label) {
|
||||
'use strict';
|
||||
|
||||
if (typeof label !== 'string') {
|
||||
throw new Error('label must be a string');
|
||||
}
|
||||
|
||||
timers[label] = Date.now();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief timeEnd
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.timeEnd = function(label) {
|
||||
'use strict';
|
||||
|
||||
var time = timers[label];
|
||||
|
||||
if (! time) {
|
||||
throw new Error('No such label: ' + label);
|
||||
}
|
||||
|
||||
var duration = Date.now() - time;
|
||||
|
||||
delete timers[label];
|
||||
|
||||
logGroup('%s: %dms', label, duration);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief trace
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.trace = function () {
|
||||
var err = new Error();
|
||||
err.name = 'trace';
|
||||
err.message = sprintf.apply(sprintf, arguments);
|
||||
Error.captureStackTrace(err, exports.trace);
|
||||
logGroup("info", err.stack);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief warn
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.warn = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
logGroup("warning", msg);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief warnLines
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.warnLines = function () {
|
||||
'use strict';
|
||||
|
||||
var msg;
|
||||
|
||||
try {
|
||||
msg = sprintf.apply(sprintf, arguments);
|
||||
}
|
||||
catch (err) {
|
||||
msg = err + ": " + arguments;
|
||||
}
|
||||
|
||||
var a = msg.split("\n");
|
||||
var i;
|
||||
|
||||
for (i = 0; i < a.length; ++i) {
|
||||
logGroup("warning", a[i]);
|
||||
}
|
||||
};
|
||||
|
||||
}());
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "/// @brief\\|/// @addtogroup\\|/// @page\\|// --SECTION--\\|/// @\\}\\|/\\*jslint"
|
||||
// End:
|
|
@ -1,5 +1,5 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
|
||||
/*global require, ArangoConnection, print, SYS_ARANGO */
|
||||
/*global require, ArangoConnection, print, SYS_ARANGO, window */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief module "internal"
|
||||
|
@ -300,6 +300,32 @@
|
|||
internal.output(level, ": ", msg, "\n");
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sprintf wrapper
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
try {
|
||||
if (window) {
|
||||
internal.sprintf = function (format) {
|
||||
var n = arguments.length;
|
||||
if (n === 0) {
|
||||
return "";
|
||||
}
|
||||
if (n <= 1) {
|
||||
return String(format);
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
|
||||
return format.replace(/%[dfs]/, function (match) {
|
||||
return String(arguments[++i]);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,432 @@
|
|||
module.define("org/arangodb/graph-blueprint", function(exports, module) {
|
||||
/*jslint indent: 2, nomen: true, maxlen: 100, sloppy: true, vars: true, white: true, plusplus: true */
|
||||
/*global require, exports */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief Graph functionality
|
||||
///
|
||||
/// @file
|
||||
///
|
||||
/// DISCLAIMER
|
||||
///
|
||||
/// Copyright 2010-2012 triagens GmbH, Cologne, Germany
|
||||
///
|
||||
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
/// you may not use this file except in compliance with the License.
|
||||
/// You may obtain a copy of the License at
|
||||
///
|
||||
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
///
|
||||
/// Unless required by applicable law or agreed to in writing, software
|
||||
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
/// See the License for the specific language governing permissions and
|
||||
/// limitations under the License.
|
||||
///
|
||||
/// Copyright holder is triAGENS GmbH, Cologne, Germany
|
||||
///
|
||||
/// @author Dr. Frank Celler, Lucas Dohmen
|
||||
/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var arangodb = require("org/arangodb"),
|
||||
is = require("org/arangodb/is"),
|
||||
common = require("org/arangodb/graph-common"),
|
||||
Edge = common.Edge,
|
||||
Graph = common.Graph,
|
||||
Vertex = common.Vertex,
|
||||
GraphArray = common.GraphArray,
|
||||
Iterator = common.Iterator,
|
||||
GraphAPI = require ("org/arangodb/api/graph").GraphAPI;
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoGraph
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief changes a property of an edge
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Edge.prototype.setProperty = function (name, value) {
|
||||
var results,
|
||||
update = this._properties;
|
||||
|
||||
update[name] = value;
|
||||
this._graph.emptyCachedPredecessors();
|
||||
|
||||
results = GraphAPI.putEdge(this._graph._properties._key, this._properties._key, update);
|
||||
|
||||
this._properties = results.edge;
|
||||
|
||||
return name;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- Vertex
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoGraph
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new vertex object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoGraph
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inbound and outbound edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.edges = function (direction, labels) {
|
||||
var edge,
|
||||
edges = new GraphArray(),
|
||||
cursor;
|
||||
|
||||
cursor = GraphAPI.postEdges(this._graph._vertices._database, this._graph._properties._key, this, {
|
||||
filter : { direction : direction, labels: labels }
|
||||
});
|
||||
|
||||
while (cursor.hasNext()) {
|
||||
edge = new Edge(this._graph, cursor.next());
|
||||
edges.push(edge);
|
||||
}
|
||||
|
||||
return edges;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inbound edges with given label
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.getInEdges = function () {
|
||||
var labels = Array.prototype.slice.call(arguments);
|
||||
return this.edges("in", labels);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief outbound edges with given label
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.getOutEdges = function () {
|
||||
var labels = Array.prototype.slice.call(arguments);
|
||||
return this.edges("out", labels);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief in- or outbound edges with given label
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.getEdges = function () {
|
||||
var labels = Array.prototype.slice.call(arguments);
|
||||
return this.edges("any", labels);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief inbound edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.inbound = function () {
|
||||
return this.getInEdges();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief outbound edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.outbound = function () {
|
||||
return this.getOutEdges();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief changes a property of a vertex
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Vertex.prototype.setProperty = function (name, value) {
|
||||
var results,
|
||||
update = this._properties;
|
||||
|
||||
update[name] = value;
|
||||
|
||||
results = GraphAPI.putVertex(this._graph._properties._key, this._properties._key, update);
|
||||
|
||||
this._properties = results.vertex;
|
||||
|
||||
return name;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- constructors and destructors
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoGraph
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief constructs a new graph object
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.initialize = function (name, vertices, edges) {
|
||||
var results;
|
||||
|
||||
if (is.notExisty(vertices) && is.notExisty(edges)) {
|
||||
results = GraphAPI.getGraph(name);
|
||||
} else {
|
||||
if (typeof vertices === 'object' && typeof vertices.name === 'function') {
|
||||
vertices = vertices.name();
|
||||
}
|
||||
if (typeof edges === 'object' && typeof edges.name === 'function') {
|
||||
edges = edges.name();
|
||||
}
|
||||
|
||||
results = GraphAPI.postGraph({
|
||||
_key: name,
|
||||
vertices: vertices,
|
||||
edges: edges
|
||||
});
|
||||
}
|
||||
|
||||
this._properties = results.graph;
|
||||
this._vertices = arangodb.db._collection(this._properties.edgeDefinitions[0].from[0]);
|
||||
this._edges = arangodb.db._collection(this._properties.edgeDefinitions[0].collection);
|
||||
|
||||
// and dictionary for vertices and edges
|
||||
this._verticesCache = {};
|
||||
this._edgesCache = {};
|
||||
|
||||
// and store the cashes
|
||||
this.predecessors = {};
|
||||
this.distances = {};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- public methods
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoGraph
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief return all graphs
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.getAll = function () {
|
||||
return GraphAPI.getAllGraphs();
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief static delete method
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.drop = function (name) {
|
||||
GraphAPI.deleteGraph(name);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief drops the graph, the vertices, and the edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.drop = function () {
|
||||
GraphAPI.deleteGraph(this._properties._key);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief saves an edge to the graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._saveEdge = function(id, out_vertex_id, in_vertex_id, params) {
|
||||
var results;
|
||||
|
||||
this.emptyCachedPredecessors();
|
||||
|
||||
params._key = id;
|
||||
params._from = out_vertex_id;
|
||||
params._to = in_vertex_id;
|
||||
|
||||
results = GraphAPI.postEdge(this._properties._key, params);
|
||||
return new Edge(this, results.edge);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief saves a vertex to the graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._saveVertex = function (id, params) {
|
||||
var results;
|
||||
|
||||
if (is.existy(id)) {
|
||||
params._key = id;
|
||||
}
|
||||
|
||||
results = GraphAPI.postVertex(this._properties._key, params);
|
||||
return new Vertex(this, results.vertex);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replace a vertex in the graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._replaceVertex = function (id, data) {
|
||||
GraphAPI.putVertex(this._properties._key, id, data);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief replace an edge in the graph
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._replaceEdge = function (id, data) {
|
||||
GraphAPI.putEdge(this._properties._key, id, data);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns a vertex given its id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.getVertex = function (id) {
|
||||
var results = GraphAPI.getVertex(this._properties._key, id);
|
||||
|
||||
if (is.notExisty(results)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Vertex(this, results.vertex);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns an iterator for all vertices
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.getVertices = function () {
|
||||
var cursor = GraphAPI.getVertices(this._vertices._database, this._properties._key, {}),
|
||||
graph = this,
|
||||
wrapper = function(object) {
|
||||
return new Vertex(graph, object);
|
||||
};
|
||||
|
||||
return new Iterator(wrapper, cursor, "[vertex iterator]");
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns an edge given its id
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.getEdge = function (id) {
|
||||
var results = GraphAPI.getEdge(this._properties._key, id);
|
||||
|
||||
if (is.notExisty(results)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new Edge(this, results.edge);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief returns an iterator for all edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.getEdges = function () {
|
||||
var cursor = GraphAPI.getEdges(this._vertices._database, this._properties._key, {}),
|
||||
graph = this,
|
||||
wrapper = function(object) {
|
||||
return new Edge(graph, object);
|
||||
};
|
||||
return new Iterator(wrapper, cursor, "[edge iterator]");
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes a vertex and all in- or out-bound edges
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.removeVertex = function (vertex) {
|
||||
this.emptyCachedPredecessors();
|
||||
GraphAPI.deleteVertex(this._properties._key, vertex._properties._key);
|
||||
vertex._properties = undefined;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief removes an edge
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype.removeEdge = function (edge) {
|
||||
this.emptyCachedPredecessors();
|
||||
GraphAPI.deleteEdge(this._properties._key, edge._properties._key);
|
||||
this._edgesCache[edge._properties._id] = undefined;
|
||||
edge._properties = undefined;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- MODULE EXPORTS
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @addtogroup ArangoGraph
|
||||
/// @{
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
exports.Edge = Edge;
|
||||
exports.Graph = Graph;
|
||||
exports.Vertex = Vertex;
|
||||
exports.GraphArray = GraphArray;
|
||||
|
||||
|
||||
require("org/arangodb/graph/algorithms-common");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Local Variables:
|
||||
// mode: outline-minor
|
||||
// outline-regexp: "^\\(/// @brief\\|/// @addtogroup\\|// --SECTION--\\|/// @page\\|/// @}\\)"
|
||||
// End:
|
||||
});
|
|
@ -5,7 +5,7 @@
|
|||
<meta charset="utf-8">
|
||||
<title>ArangoDB Web Interface</title>
|
||||
<meta name="description" content="ArangoDB Admin Web Interface">
|
||||
<meta name="author" content="Heiko Kernbach, Michael Hacksteina, Guido Schwab">
|
||||
<meta name="author" content="Heiko Kernbach, Michael Hackstein, Guido Schwab">
|
||||
<link href="css/style.css" rel="stylesheet">
|
||||
<link href="css/sass.css" rel="stylesheet">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
|
||||
|
|
|
@ -102,6 +102,7 @@
|
|||
"frontend/js/bootstrap/module-internal.js",
|
||||
"frontend/js/client/bootstrap/module-internal.js",
|
||||
"frontend/js/client/client.js",
|
||||
"frontend/js/bootstrap/module-console.js",
|
||||
"frontend/js/models/arangoCollectionModel.js",
|
||||
"frontend/js/models/arangoDatabase.js",
|
||||
"frontend/js/models/arangoDocument.js",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*jslint indent: 2, nomen: true, maxlen: 120, sloppy: true, vars: true, white: true, plusplus: true, nonpropdel: true */
|
||||
/*global require, ArangoConnection, print, SYS_ARANGO */
|
||||
/*global require, ArangoConnection, print, SYS_ARANGO, window */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief module "internal"
|
||||
|
@ -300,6 +300,32 @@
|
|||
internal.output(level, ": ", msg, "\n");
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief sprintf wrapper
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
try {
|
||||
if (window) {
|
||||
internal.sprintf = function (format) {
|
||||
var n = arguments.length;
|
||||
if (n === 0) {
|
||||
return "";
|
||||
}
|
||||
if (n <= 1) {
|
||||
return String(format);
|
||||
}
|
||||
|
||||
var i = 0;
|
||||
|
||||
return format.replace(/%[dfs]/, function (match) {
|
||||
return String(arguments[++i]);
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @}
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -215,6 +215,7 @@
|
|||
"ERROR_GRAPH_DUPLICATE" : { "code" : 1925, "message" : "graph already exists" },
|
||||
"ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST" : { "code" : 1926, "message" : "collection does not exist" },
|
||||
"ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX" : { "code" : 1927, "message" : "not a vertex collection" },
|
||||
"ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION" : { "code" : 1928, "message" : "not in orphan collection" },
|
||||
"ERROR_SESSION_UNKNOWN" : { "code" : 1950, "message" : "unknown session" },
|
||||
"ERROR_SESSION_EXPIRED" : { "code" : 1951, "message" : "session expired" },
|
||||
"SIMPLE_CLIENT_UNKNOWN_ERROR" : { "code" : 2000, "message" : "unknown client error" },
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*jslint indent: 2, maxlen: 120, vars: true, white: true, plusplus: true, nonpropdel: true, sloppy: true */
|
||||
/*global require, SYS_GETLINE, SYS_LOG */
|
||||
/*global require, SYS_GETLINE, SYS_LOG, jqconsole */
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief module "console"
|
||||
|
@ -64,8 +64,21 @@
|
|||
/// @brief internal logging
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
var log = SYS_LOG;
|
||||
delete SYS_LOG;
|
||||
var log;
|
||||
|
||||
try {
|
||||
// this will work when we are in arangod but not in the browser / web interface
|
||||
log = SYS_LOG;
|
||||
delete SYS_LOG;
|
||||
}
|
||||
catch (err) {
|
||||
// this will work in the web interface
|
||||
log = function (level, message) {
|
||||
if (jqconsole) {
|
||||
jqconsole.Write(message + "\n", 'jssuccess');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief internal logging with group level
|
||||
|
|
|
@ -1709,7 +1709,7 @@ var Graph = function(graphName, edgeDefinitions, vertexCollections, edgeCollecti
|
|||
createHiddenProperty(this, "__edgeDefinitions", edgeDefinitions);
|
||||
createHiddenProperty(this, "__idsToRemove", []);
|
||||
createHiddenProperty(this, "__collectionsToLock", []);
|
||||
createHiddenProperty(this, "__singleVertexCollections", []);
|
||||
createHiddenProperty(this, "__orphanCollections", []);
|
||||
|
||||
// fills this.__idsToRemove and this.__collectionsToLock
|
||||
var removeEdge = function (edgeId, options) {
|
||||
|
@ -1958,6 +1958,12 @@ var checkIfMayBeDropped = function(colName, graphName, graphs) {
|
|||
}
|
||||
);
|
||||
}
|
||||
var orphanCollections = graph.orphanCollections;
|
||||
if (orphanCollections) {
|
||||
if (orphanCollections.indexOf(colName) !== -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -2691,28 +2697,29 @@ Graph.prototype._deleteEdgeDefinition = function(edgeCollection, dropCollections
|
|||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock JSF_general_graph__addVertexCollection
|
||||
/// Adds a vertex collection to the graph. If the collection does not exist, it will be created.
|
||||
/// @startDocuBlock JSF_general_graph__addOrphanCollection
|
||||
/// Adds a vertex collection to the set of orphan collections of the graph. If the
|
||||
/// collection does not exist, it will be created.
|
||||
///
|
||||
/// `general-graph._addVertexCollection(vertexCollectionName, createCollection)`
|
||||
/// `general-graph._addOrphanCollection(orphanCollectionName, createCollection)`
|
||||
///
|
||||
/// *vertexCollectionName* - string : name of vertex collection.
|
||||
/// *orphanCollectionName* - string : name of vertex collection.
|
||||
/// *createCollection* - bool : if true the collection will be created if it does not exist. Default: true.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addeleteVertexCollection}
|
||||
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__addOrphanCollection}
|
||||
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
|
||||
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
|
||||
/// var g = examples._create("myGraph", [ed1, ed2]);
|
||||
/// g._addVertexCollection("myVC3", true);
|
||||
/// g._addOrphanCollection("myVC3", true);
|
||||
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
||||
///
|
||||
/// @endDocuBlock
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._addVertexCollection = function(vertexCollection, createCollection) {
|
||||
Graph.prototype._addOrphanCollection = function(vertexCollection, createCollection) {
|
||||
//check edgeCollection
|
||||
var ec = db._collection(vertexCollection);
|
||||
var err;
|
||||
|
@ -2725,20 +2732,93 @@ Graph.prototype._addVertexCollection = function(vertexCollection, createCollecti
|
|||
err.errorMessage = vertexCollection + arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
|
||||
throw err;
|
||||
}
|
||||
} else if (ec.type !== 3) {
|
||||
//TODO
|
||||
} else if (ec.type() !== 2) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message;
|
||||
throw err;
|
||||
}
|
||||
|
||||
this.__singleVertexCollections.push(vertexCollection);
|
||||
this.__orphanCollections.push(vertexCollection);
|
||||
db._graphs.update(this.__name, {orphanCollections: this.__orphanCollections});
|
||||
|
||||
};
|
||||
|
||||
Graph.prototype._getVertexCollections = function() {
|
||||
return this.__singleVertexCollections;
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock JSF_general_graph__getOrphanCollections
|
||||
/// Returns all vertex collections of the graph, that are not used in an edge definition.
|
||||
///
|
||||
/// `general-graph._getOrphanCollections()`
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
|
||||
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
|
||||
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
|
||||
/// var g = examples._create("myGraph", [ed1]);
|
||||
/// g._addOrphanCollection("myVC3, true);
|
||||
/// g._getOrphanCollections();
|
||||
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
||||
///
|
||||
/// @endDocuBlock
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._getOrphanCollections = function() {
|
||||
return this.__orphanCollections;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @startDocuBlock JSF_general_graph__removeOrphanCollection
|
||||
/// Removes an orphan collection from the graph and deletes the collection, if it is not
|
||||
/// used in any graph.
|
||||
///
|
||||
/// `general-graph._removeOrphanCollection()`
|
||||
///
|
||||
/// *orphanCollectionName* - string : name of vertex collection.
|
||||
/// *dropCollection* - bool : if true the collection will be dropped if it is not used in any graph.
|
||||
/// Default: true.
|
||||
///
|
||||
/// @EXAMPLES
|
||||
///
|
||||
/// @EXAMPLE_ARANGOSH_OUTPUT{general_graph__getOrphanCollections}
|
||||
/// var examples = require("org/arangodb/graph-examples/example-graph.js");
|
||||
/// var ed1 = examples._directedRelationDefinition("myEC1", ["myVC1"], ["myVC2"]);
|
||||
/// var g = examples._create("myGraph", [ed1]);
|
||||
/// g._addOrphanCollection("myVC3, true);
|
||||
/// g._addOrphanCollection("myVC4, true);
|
||||
/// g._getOrphanCollections();
|
||||
/// g._removeOrphanCollection("myVC3");
|
||||
/// g._getOrphanCollections();
|
||||
/// @END_EXAMPLE_ARANGOSH_OUTPUT
|
||||
///
|
||||
/// @endDocuBlock
|
||||
///
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Graph.prototype._removeOrphanCollection = function(orphanCollectionName, dropCollection) {
|
||||
var err;
|
||||
if (db._collection(orphanCollectionName) === null) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message;
|
||||
throw err;
|
||||
}
|
||||
var index = this.__orphanCollections.indexOf(orphanCollectionName);
|
||||
if (index === -1) {
|
||||
err = new ArangoError();
|
||||
err.errorNum = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code;
|
||||
err.errorMessage = arangodb.errors.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message;
|
||||
throw err;
|
||||
}
|
||||
this.__orphanCollections.splice(index, 1);
|
||||
|
||||
if (dropCollection !== false) {
|
||||
var graphs = getGraphCollection().toArray();
|
||||
if (checkIfMayBeDropped(orphanCollectionName, null, graphs)) {
|
||||
db._drop(orphanCollectionName);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -2497,7 +2497,7 @@ function GeneralGraphCommonNeighborsSuite() {
|
|||
};
|
||||
}
|
||||
|
||||
function VertexCollectionSuite() {
|
||||
function OrphanCollectionSuite() {
|
||||
var prefix = "UnitTestGraphVertexCollection",
|
||||
g1,
|
||||
g2,
|
||||
|
@ -2543,42 +2543,66 @@ function VertexCollectionSuite() {
|
|||
tearDown : function() {
|
||||
graph._drop(gN1);
|
||||
graph._drop(gN2);
|
||||
try {db[vC1].drop()} catch (e) {}
|
||||
try {db[vC4].drop()} catch (e) {}
|
||||
},
|
||||
|
||||
test_addVertexCollection1: function() {
|
||||
g1._addVertexCollection(vC1, false);
|
||||
assertEqual(g1._getVertexCollections(), [vC1]);
|
||||
test_getOrphanCollection: function() {
|
||||
assertEqual(g1._getOrphanCollections(), []);
|
||||
},
|
||||
|
||||
test_addVertexCollection2: function() {
|
||||
test_addOrphanCollection1: function() {
|
||||
g1._addOrphanCollection(vC1, false);
|
||||
assertEqual(g1._getOrphanCollections(), [vC1]);
|
||||
},
|
||||
|
||||
test_addOrphanCollection2: function() {
|
||||
try {
|
||||
g1._addVertexCollection(vC4, false);
|
||||
g1._addOrphanCollection(vC4, false);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
|
||||
assertEqual(e.errorMessage, vC4 + ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
|
||||
}
|
||||
assertTrue(db._collection(vC4) === null);
|
||||
assertEqual(g1._getVertexCollections(), []);
|
||||
assertEqual(g1._getOrphanCollections(), []);
|
||||
},
|
||||
|
||||
test_addVertexCollection3: function() {
|
||||
test_addOrphanCollection3: function() {
|
||||
try {
|
||||
g1._addVertexCollection(eC1, false);
|
||||
g1._addOrphanCollection(eC1, false);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.code);
|
||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX.message);
|
||||
}
|
||||
assertTrue(db._collection(vC4) === null);
|
||||
assertEqual(g1._getVertexCollections(), []);
|
||||
assertEqual(g1._getOrphanCollections(), []);
|
||||
},
|
||||
|
||||
test_addVertexCollection4: function() {
|
||||
g1._addVertexCollection(vC4);
|
||||
assertEqual(g1._getVertexCollections(), [vC4]);
|
||||
assertTrue(db._collection(vC4) !== null);
|
||||
test_removeOrphanCollection1: function() {
|
||||
var name = "completelyNonsenseNameForACollectionBLUBBBBB"
|
||||
try {
|
||||
g1._removeOrphanCollection(name);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.code);
|
||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST.message);
|
||||
}
|
||||
},
|
||||
|
||||
test_removeOrphanCollection2: function() {
|
||||
g1._addOrphanCollection(vC4, true);
|
||||
g1._addOrphanCollection(vC5, true);
|
||||
assertEqual(g1._getOrphanCollections(), [vC4, vC5]);
|
||||
g1._removeOrphanCollection(vC4, false);
|
||||
assertEqual(g1._getOrphanCollections(), [vC5]);
|
||||
try {
|
||||
g1._removeOrphanCollection(vC4);
|
||||
} catch (e) {
|
||||
assertEqual(e.errorNum, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.code);
|
||||
assertEqual(e.errorMessage, ERRORS.ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION.message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -2599,7 +2623,7 @@ jsunity.run(GeneralGraphAQLQueriesSuite);
|
|||
jsunity.run(EdgesAndVerticesSuite);
|
||||
jsunity.run(GeneralGraphCreationSuite);
|
||||
jsunity.run(ChainedFluentAQLResultsSuite);
|
||||
//jsunity.run(VertexCollectionSuite);
|
||||
jsunity.run(OrphanCollectionSuite);
|
||||
|
||||
return jsunity.done();
|
||||
|
||||
|
|
|
@ -30,11 +30,16 @@
|
|||
|
||||
var Controller = require("org/arangodb/foxx/controller").Controller,
|
||||
Model = require("org/arangodb/foxx/model").Model,
|
||||
Repository = require("org/arangodb/foxx/repository").Repository;
|
||||
Repository = require("org/arangodb/foxx/repository").Repository,
|
||||
manager = require("org/arangodb/foxx/manager"),
|
||||
arangodb = require("org/arangodb");
|
||||
|
||||
exports.Controller = Controller;
|
||||
exports.Model = Model;
|
||||
exports.Repository = Repository;
|
||||
exports.requireApp = function(path) {
|
||||
return manager.mountedApp(arangodb.normalizeURL('/' + path));
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// --SECTION-- END-OF-FILE
|
||||
|
|
|
@ -115,6 +115,12 @@ Controller = function (context, options) {
|
|||
|
||||
context.foxxes.push(this);
|
||||
|
||||
if (is.existy(context.manifest.rootElement)) {
|
||||
this.rootElement =context.manifest.rootElement;
|
||||
} else {
|
||||
this.rootElement = false;
|
||||
}
|
||||
|
||||
this.applicationContext = context;
|
||||
};
|
||||
|
||||
|
@ -123,22 +129,8 @@ extend(Controller.prototype, {
|
|||
|
||||
collection: function (name) {
|
||||
'use strict';
|
||||
var collection, cname, prefix;
|
||||
prefix = this.collectionPrefix;
|
||||
|
||||
if (prefix === "") {
|
||||
cname = name;
|
||||
} else {
|
||||
cname = prefix + "_" + name;
|
||||
}
|
||||
cname = cname.replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
|
||||
|
||||
collection = db._collection(cname);
|
||||
|
||||
if (!collection) {
|
||||
throw new Error("collection with name '" + cname + "' does not exist.");
|
||||
}
|
||||
return collection;
|
||||
require('console').log('Controller#collection is deprecated, use appContext#collection instead');
|
||||
return this.applicationContext.collection(name);
|
||||
},
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -156,7 +148,7 @@ extend(Controller.prototype, {
|
|||
handleRequest: function (method, route, callback) {
|
||||
'use strict';
|
||||
var newRoute = internal.constructRoute(method, route, callback),
|
||||
requestContext = new RequestContext(this.allRoutes, this.models, newRoute),
|
||||
requestContext = new RequestContext(this.allRoutes, this.models, newRoute, this.rootElement),
|
||||
summary;
|
||||
|
||||
this.routingInfo.routes.push(newRoute);
|
||||
|
@ -294,7 +286,7 @@ extend(Controller.prototype, {
|
|||
///
|
||||
/// This handles requests from the HTTP verb `delete`. See above for the
|
||||
/// arguments you can give.
|
||||
///
|
||||
///
|
||||
/// @warning Do not forget that `delete` is a reserved word in JavaScript and
|
||||
/// therefore needs to be called as app['delete']. There is also an alias `del`
|
||||
/// for this very reason.
|
||||
|
|
|
@ -102,7 +102,7 @@ function checkManifest (filename, mf) {
|
|||
// add a default (empty) description
|
||||
mf.description = "";
|
||||
}
|
||||
|
||||
|
||||
if (mf.hasOwnProperty("apps")) {
|
||||
console.warn("Manifest '%s' still contains the deprecated 'apps' attribute. " +
|
||||
"Please change the attribute name to 'controllers'.", filename);
|
||||
|
@ -121,7 +121,7 @@ function checkManifest (filename, mf) {
|
|||
"assets": [ false, "object" ],
|
||||
"author": [ false, "string" ],
|
||||
"contributors": [ false, "array" ],
|
||||
"controllers": [ true, "object" ],
|
||||
"controllers": [ false, "object" ],
|
||||
"defaultDocument": [ false, "string" ],
|
||||
"description": [ true, "string" ],
|
||||
"engines": [ false, "object" ],
|
||||
|
@ -136,6 +136,7 @@ function checkManifest (filename, mf) {
|
|||
"teardown": [ false, "string" ],
|
||||
"thumbnail": [ false, "string" ],
|
||||
"version": [ true, "string" ],
|
||||
"rootElement": [ false, "boolean" ],
|
||||
"exports": [ false, "object" ]
|
||||
};
|
||||
|
||||
|
@ -148,8 +149,8 @@ function checkManifest (filename, mf) {
|
|||
var actualType = Array.isArray(mf[att]) ? "array" : typeof(mf[att]);
|
||||
|
||||
if (actualType !== expectedType) {
|
||||
console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'",
|
||||
filename,
|
||||
console.error("Manifest '%s' uses an invalid data type (%s) for %s attribute '%s'",
|
||||
filename,
|
||||
actualType,
|
||||
expectedType,
|
||||
att);
|
||||
|
@ -160,8 +161,8 @@ function checkManifest (filename, mf) {
|
|||
// attribute not present in manifest
|
||||
if (expected[att][0]) {
|
||||
// required attribute
|
||||
console.error("Manifest '%s' does not provide required attribute '%s'",
|
||||
filename,
|
||||
console.error("Manifest '%s' does not provide required attribute '%s'",
|
||||
filename,
|
||||
att);
|
||||
|
||||
failed = true;
|
||||
|
@ -169,7 +170,7 @@ function checkManifest (filename, mf) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (failed) {
|
||||
throw new Error("Manifest '%s' is invalid/incompatible. Please check the error logs.");
|
||||
}
|
||||
|
@ -178,8 +179,8 @@ function checkManifest (filename, mf) {
|
|||
for (att in mf) {
|
||||
if (mf.hasOwnProperty(att)) {
|
||||
if (! expected.hasOwnProperty(att)) {
|
||||
console.warn("Manifest '%s' contains an unknown attribute '%s'",
|
||||
filename,
|
||||
console.warn("Manifest '%s' contains an unknown attribute '%s'",
|
||||
filename,
|
||||
att);
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +209,10 @@ function extendContext (context, app, root) {
|
|||
return replaced;
|
||||
};
|
||||
|
||||
context.collection = function (name) {
|
||||
return arangodb.db._collection(this.collectionName(name));
|
||||
};
|
||||
|
||||
context.path = function (name) {
|
||||
return fs.join(root, app._path, name);
|
||||
};
|
||||
|
@ -279,7 +284,7 @@ function buildAssetContent (app, assets, basePath) {
|
|||
|
||||
var excludeFile = function (name) {
|
||||
var parts = name.split('/');
|
||||
|
||||
|
||||
if (parts.length > 0) {
|
||||
var last = parts[parts.length - 1];
|
||||
|
||||
|
@ -303,8 +308,8 @@ function buildAssetContent (app, assets, basePath) {
|
|||
|
||||
if (match !== null) {
|
||||
m = fs.listTree(fs.join(basePath, match[1]));
|
||||
|
||||
// files are sorted in file-system order.
|
||||
|
||||
// files are sorted in file-system order.
|
||||
// this makes the order non-portable
|
||||
// we'll be sorting the files now using JS sort
|
||||
// so the order is more consistent across multiple platforms
|
||||
|
@ -312,7 +317,7 @@ function buildAssetContent (app, assets, basePath) {
|
|||
|
||||
for (i = 0; i < m.length; ++i) {
|
||||
var filename = fs.join(basePath, match[1], m[i]);
|
||||
|
||||
|
||||
if (! excludeFile(m[i])) {
|
||||
if (fs.isFile(filename)) {
|
||||
files.push(filename);
|
||||
|
@ -322,7 +327,7 @@ function buildAssetContent (app, assets, basePath) {
|
|||
}
|
||||
else {
|
||||
match = reAll.exec(asset);
|
||||
|
||||
|
||||
if (match !== null) {
|
||||
throw new Error("Not implemented");
|
||||
}
|
||||
|
@ -367,7 +372,7 @@ function buildFileAsset (app, path, basePath, asset) {
|
|||
type = asset.contentType;
|
||||
}
|
||||
|
||||
// path contains a dot, derive content type from path
|
||||
// path contains a dot, derive content type from path
|
||||
else if (path.match(/\.[a-zA-Z0-9]+$/)) {
|
||||
type = arangodb.guessContentType(path);
|
||||
}
|
||||
|
@ -399,7 +404,7 @@ function buildDevelopmentAssetRoute (app, path, basePath, asset) {
|
|||
|
||||
return {
|
||||
url: { match: path },
|
||||
action: {
|
||||
action: {
|
||||
callback: function (req, res) {
|
||||
var c = buildFileAsset(app, path, basePath, asset);
|
||||
|
||||
|
@ -495,7 +500,7 @@ function installAssets (app, routes) {
|
|||
|
||||
function executeAppScript (app, name, mount, prefix) {
|
||||
var desc = app._manifest;
|
||||
|
||||
|
||||
if (! desc) {
|
||||
throw new Error("Invalid application manifest, app " + arangodb.inspect(app));
|
||||
}
|
||||
|
@ -527,6 +532,7 @@ function executeAppScript (app, name, mount, prefix) {
|
|||
|
||||
appContext.isDevelopment = devel;
|
||||
appContext.isProduction = ! devel;
|
||||
appContext.manifest = app._manifest;
|
||||
|
||||
extendContext(appContext, app, root);
|
||||
|
||||
|
@ -557,10 +563,10 @@ function teardownApp (app, mount, prefix) {
|
|||
|
||||
function upsertAalAppEntry (manifest, thumbnail, path) {
|
||||
var aal = getStorage();
|
||||
var doc = aal.firstExample({
|
||||
type: "app",
|
||||
name: manifest.name,
|
||||
version: manifest.version
|
||||
var doc = aal.firstExample({
|
||||
type: "app",
|
||||
name: manifest.name,
|
||||
version: manifest.version
|
||||
});
|
||||
|
||||
if (doc === null) {
|
||||
|
@ -610,7 +616,7 @@ function mountAalApp (app, mount, options) {
|
|||
var find = aal.firstExample({ type: "mount", mount: mount, active: true });
|
||||
|
||||
if (find !== null) {
|
||||
throw new Error("Cannot use mount path '" + mount + "', already used by '"
|
||||
throw new Error("Cannot use mount path '" + mount + "', already used by '"
|
||||
+ find.app + "' (" + find._key + ")");
|
||||
}
|
||||
|
||||
|
@ -747,6 +753,8 @@ function routingAalApp (app, mount, options) {
|
|||
appContextTempl.isDevelopment = devel;
|
||||
appContextTempl.isProduction = ! devel;
|
||||
|
||||
appContextTempl.manifest = app._manifest;
|
||||
|
||||
var appContext;
|
||||
var file;
|
||||
|
||||
|
@ -815,13 +823,13 @@ function routingAalApp (app, mount, options) {
|
|||
|
||||
for (j = 0; j < rt.length; ++j) {
|
||||
route = rt[j];
|
||||
|
||||
|
||||
if (route.hasOwnProperty("url")) {
|
||||
route.url.match = arangodb.normalizeURL(p + "/" + route.url.match);
|
||||
}
|
||||
|
||||
route.context = i;
|
||||
|
||||
|
||||
routes[key].push(route);
|
||||
}
|
||||
}
|
||||
|
@ -910,16 +918,16 @@ function scanDirectory (path) {
|
|||
|
||||
exports.scanAppDirectory = function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
var aal = getStorage();
|
||||
|
||||
// remove all loaded apps first
|
||||
aal.removeByExample({ type: "app" });
|
||||
|
||||
// now re-scan, starting with system apps
|
||||
scanDirectory(module.systemAppPath());
|
||||
scanDirectory(module.systemAppPath());
|
||||
// now scan database-specific apps
|
||||
scanDirectory(module.appPath());
|
||||
scanDirectory(module.appPath());
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -1214,7 +1222,7 @@ exports.devSetup = function (filename) {
|
|||
|
||||
var root = module.devAppPath();
|
||||
var m = fs.join(root, filename, "manifest.json");
|
||||
|
||||
|
||||
if (fs.exists(m)) {
|
||||
try {
|
||||
var mf = JSON.parse(fs.read(m));
|
||||
|
@ -1262,7 +1270,7 @@ exports.devTeardown = function (filename) {
|
|||
|
||||
var root = module.devAppPath();
|
||||
var m = fs.join(root, filename, "manifest.json");
|
||||
|
||||
|
||||
if (fs.exists(m)) {
|
||||
try {
|
||||
var mf = JSON.parse(fs.read(m));
|
||||
|
@ -1296,7 +1304,7 @@ exports.devTeardown = function (filename) {
|
|||
|
||||
exports.appRoutes = function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
var aal = getStorage();
|
||||
|
||||
return arangodb.db._executeTransaction({
|
||||
|
@ -1327,7 +1335,7 @@ exports.appRoutes = function () {
|
|||
var r = routingAalApp(app, mount, options);
|
||||
|
||||
if (r === null) {
|
||||
throw new Error("Cannot compute the routing table for Foxx application '"
|
||||
throw new Error("Cannot compute the routing table for Foxx application '"
|
||||
+ app._id + "', check the log file for errors!");
|
||||
}
|
||||
|
||||
|
@ -1367,7 +1375,7 @@ exports.developmentRoutes = function () {
|
|||
if (fs.exists(m)) {
|
||||
try {
|
||||
var mf = JSON.parse(fs.read(m));
|
||||
|
||||
|
||||
checkManifest(m, mf);
|
||||
|
||||
var appId = "dev:" + mf.name + ":" + files[j];
|
||||
|
@ -1387,7 +1395,7 @@ exports.developmentRoutes = function () {
|
|||
var r = routingAalApp(app, mount, options);
|
||||
|
||||
if (r === null) {
|
||||
throw new Error("Cannot compute the routing table for Foxx application '"
|
||||
throw new Error("Cannot compute the routing table for Foxx application '"
|
||||
+ app._id + "', check the log file for errors!");
|
||||
}
|
||||
|
||||
|
|
|
@ -40,14 +40,46 @@ var RequestContext,
|
|||
createBodyParamBubbleWrap,
|
||||
addCheck;
|
||||
|
||||
createBodyParamBubbleWrap = function (handler, paramName, Proto) {
|
||||
var elementExtractFactory = function(paramName, rootElement) {
|
||||
var extractElement;
|
||||
|
||||
if (rootElement) {
|
||||
extractElement = function (req) {
|
||||
return req.body()[paramName];
|
||||
};
|
||||
} else {
|
||||
extractElement = function (req) {
|
||||
return req.body();
|
||||
};
|
||||
}
|
||||
|
||||
return extractElement;
|
||||
};
|
||||
|
||||
var bubbleWrapFactory = function (handler, paramName, Proto, extractElement, multiple) {
|
||||
'use strict';
|
||||
if (multiple) {
|
||||
Proto = Proto[0];
|
||||
}
|
||||
|
||||
return function (req, res) {
|
||||
req.parameters[paramName] = new Proto(req.body());
|
||||
if (multiple) {
|
||||
req.parameters[paramName] = _.map(extractElement(req), function (raw) {
|
||||
return new Proto(raw);
|
||||
});
|
||||
} else {
|
||||
req.parameters[paramName] = new Proto(extractElement(req));
|
||||
}
|
||||
handler(req, res);
|
||||
};
|
||||
};
|
||||
|
||||
createBodyParamBubbleWrap = function (handler, paramName, Proto, rootElement) {
|
||||
'use strict';
|
||||
var extractElement = elementExtractFactory(paramName, rootElement);
|
||||
return bubbleWrapFactory(handler, paramName, Proto, extractElement, is.array(Proto));
|
||||
};
|
||||
|
||||
createErrorBubbleWrap = function (handler, errorClass, code, reason, errorHandler) {
|
||||
'use strict';
|
||||
if (is.notExisty(errorHandler)) {
|
||||
|
@ -137,7 +169,7 @@ extend(SwaggerDocs.prototype, {
|
|||
/// Used for documenting and constraining the routes.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RequestContext = function (executionBuffer, models, route) {
|
||||
RequestContext = function (executionBuffer, models, route, rootElement) {
|
||||
'use strict';
|
||||
this.route = route;
|
||||
this.typeToRegex = {
|
||||
|
@ -145,6 +177,7 @@ RequestContext = function (executionBuffer, models, route) {
|
|||
"integer": "/[0-9]+/",
|
||||
"string": "/[^/]+/"
|
||||
};
|
||||
this.rootElement = rootElement;
|
||||
|
||||
this.docs = new SwaggerDocs(this.route.docs, models);
|
||||
this.docs.addNickname(route.docs.httpMethod, route.url.match);
|
||||
|
@ -249,14 +282,30 @@ extend(RequestContext.prototype, {
|
|||
/// This will initialize a `Model` with the data and provide it to you via the
|
||||
/// params as `paramName`.
|
||||
/// For information about how to annotate your models, see the Model section.
|
||||
/// If you provide the Model in an array, the response will take multiple models
|
||||
/// instead of one.
|
||||
///
|
||||
/// If you wrap the provided model in an array, the body param is always an array
|
||||
/// and accordingly the return value of the `params` for the body call will also
|
||||
/// return an array of models.
|
||||
///
|
||||
/// The behavior of `bodyParam` changes depending on the `rootElement` option
|
||||
/// set in the manifest. If it is set to true, it is expected that the body is an
|
||||
/// object with a key of the same name as the `paramName` argument.
|
||||
/// The value of this object is either a single object or in the case of a multi
|
||||
/// element an array of objects.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bodyParam: function (paramName, description, Proto) {
|
||||
'use strict';
|
||||
var handler = this.route.action.callback;
|
||||
|
||||
this.docs.addBodyParam(paramName, description, Proto.toJSONSchema(paramName));
|
||||
this.route.action.callback = createBodyParamBubbleWrap(handler, paramName, Proto);
|
||||
if (is.array(Proto)) {
|
||||
this.docs.addBodyParam(paramName, description, Proto[0].toJSONSchema(paramName));
|
||||
} else {
|
||||
this.docs.addBodyParam(paramName, description, Proto.toJSONSchema(paramName));
|
||||
}
|
||||
this.route.action.callback = createBodyParamBubbleWrap(handler, paramName, Proto, this.rootElement);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
|
|
@ -3,7 +3,9 @@ require("internal").flushModuleCache();
|
|||
var jsunity = require("jsunity"),
|
||||
FoxxController = require("org/arangodb/foxx").Controller,
|
||||
db = require("org/arangodb").db,
|
||||
_ = require("underscore"),
|
||||
fakeContext,
|
||||
fakeContextWithRootElement,
|
||||
stub_and_mock = require("org/arangodb/stub_and_mock"),
|
||||
stub = stub_and_mock.stub,
|
||||
allow = stub_and_mock.allow,
|
||||
|
@ -13,6 +15,21 @@ fakeContext = {
|
|||
prefix: "",
|
||||
foxxes: [],
|
||||
comments: [],
|
||||
manifest: {
|
||||
rootElement: false
|
||||
},
|
||||
clearComments: function () {},
|
||||
comment: function () {},
|
||||
collectionName: function () {}
|
||||
};
|
||||
|
||||
fakeContextWithRootElement = {
|
||||
prefix: "",
|
||||
foxxes: [],
|
||||
comments: [],
|
||||
manifest: {
|
||||
rootElement: true
|
||||
},
|
||||
clearComments: function () {},
|
||||
comment: function () {},
|
||||
collectionName: function () {}
|
||||
|
@ -283,7 +300,7 @@ function DocumentationAndConstraintsSpec () {
|
|||
|
||||
assertEqual(routes.length, 1);
|
||||
|
||||
assertEqual(routes[0].url.constraint.foxx, "/.+/");
|
||||
assertEqual(routes[0].url.constraint.foxx, "/[^/]+/");
|
||||
assertEqual(routes[0].docs.parameters[0].paramType, "path");
|
||||
assertEqual(routes[0].docs.parameters[0].name, "foxx");
|
||||
assertEqual(routes[0].docs.parameters[0].description, "Kind of Foxx");
|
||||
|
@ -309,7 +326,7 @@ function DocumentationAndConstraintsSpec () {
|
|||
|
||||
assertEqual(routes.length, 1);
|
||||
|
||||
assertEqual(routes[0].url.constraint.foxxParam, "/.+/");
|
||||
assertEqual(routes[0].url.constraint.foxxParam, "/[^/]+/");
|
||||
assertEqual(routes[0].docs.parameters[0].paramType, "path");
|
||||
assertEqual(routes[0].docs.parameters[0].name, "foxxParam");
|
||||
assertEqual(routes[0].docs.parameters[0].description, "Kind of Foxx");
|
||||
|
@ -362,6 +379,27 @@ function DocumentationAndConstraintsSpec () {
|
|||
assertEqual(routes[0].docs.parameters[0].dataType, jsonSchema.id);
|
||||
},
|
||||
|
||||
testAddBodyParamWithMultipleItems: function () {
|
||||
var paramName = stub(),
|
||||
description = stub(),
|
||||
ModelPrototype = stub(),
|
||||
jsonSchema = { id: 'a', required: [], properties: {} };
|
||||
|
||||
allow(ModelPrototype)
|
||||
.toReceive("toJSONSchema")
|
||||
.andReturn(jsonSchema);
|
||||
|
||||
app.get('/foxx', function () {
|
||||
//nothing
|
||||
}).bodyParam(paramName, description, [ModelPrototype]);
|
||||
|
||||
assertEqual(routes.length, 1);
|
||||
assertEqual(routes[0].docs.parameters[0].name, paramName);
|
||||
assertEqual(routes[0].docs.parameters[0].paramType, "body");
|
||||
assertEqual(routes[0].docs.parameters[0].description, description);
|
||||
assertEqual(routes[0].docs.parameters[0].dataType, jsonSchema.id);
|
||||
},
|
||||
|
||||
testDefineBodyParamAddsJSONSchemaToModels: function () {
|
||||
var paramName = stub(),
|
||||
description = stub(),
|
||||
|
@ -406,6 +444,34 @@ function DocumentationAndConstraintsSpec () {
|
|||
ModelPrototype.assertIsSatisfied();
|
||||
},
|
||||
|
||||
testSetParamForBodyParamWithMultipleItems: function () {
|
||||
var req = { parameters: {} },
|
||||
res = {},
|
||||
paramName = stub(),
|
||||
description = stub(),
|
||||
rawElement = stub(),
|
||||
requestBody = [rawElement],
|
||||
ModelPrototype = stub(),
|
||||
jsonSchemaId = stub(),
|
||||
called = false;
|
||||
|
||||
allow(req)
|
||||
.toReceive("body")
|
||||
.andReturn(requestBody);
|
||||
|
||||
ModelPrototype = mockConstructor(rawElement);
|
||||
ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
|
||||
|
||||
app.get('/foxx', function (providedReq) {
|
||||
called = (providedReq.parameters[paramName][0] instanceof ModelPrototype);
|
||||
}).bodyParam(paramName, description, [ModelPrototype]);
|
||||
|
||||
routes[0].action.callback(req, res);
|
||||
|
||||
assertTrue(called);
|
||||
ModelPrototype.assertIsSatisfied();
|
||||
},
|
||||
|
||||
testDocumentationForErrorResponse: function () {
|
||||
var CustomErrorClass = function () {};
|
||||
|
||||
|
@ -639,36 +705,6 @@ function CommentDrivenDocumentationSpec () {
|
|||
};
|
||||
}
|
||||
|
||||
function HelperFunctionSpec () {
|
||||
var app;
|
||||
|
||||
return {
|
||||
setUp: function () {
|
||||
fakeContext.collectionPrefix = "fancy";
|
||||
app = new FoxxController(fakeContext);
|
||||
},
|
||||
|
||||
testGetACollection: function () {
|
||||
db._create("fancy_pants");
|
||||
|
||||
assertEqual(app.collection("pants"), db._collection("fancy_pants"));
|
||||
},
|
||||
|
||||
testGetACollectionThatDoesNotExist: function () {
|
||||
var err;
|
||||
db._drop("fancy_pants");
|
||||
|
||||
try {
|
||||
app.collection("pants");
|
||||
} catch(e) {
|
||||
err = e;
|
||||
}
|
||||
|
||||
assertEqual(err.message, "collection with name 'fancy_pants' does not exist.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function SetupAuthorization () {
|
||||
var app;
|
||||
|
||||
|
@ -767,12 +803,79 @@ function SetupAuthorization () {
|
|||
};
|
||||
}
|
||||
|
||||
function FoxxControllerWithRootElement () {
|
||||
var app;
|
||||
|
||||
return {
|
||||
setUp: function () {
|
||||
app = new FoxxController(fakeContextWithRootElement);
|
||||
routes = app.routingInfo.routes;
|
||||
},
|
||||
|
||||
testBodyParamWithOneElement: function () {
|
||||
var req = { parameters: {} },
|
||||
res = {},
|
||||
paramName = 'myBodyParam',
|
||||
description = stub(),
|
||||
rawElement = stub(),
|
||||
requestBody = { myBodyParam: rawElement },
|
||||
ModelPrototype = stub(),
|
||||
jsonSchemaId = stub(),
|
||||
called = false;
|
||||
|
||||
allow(req)
|
||||
.toReceive("body")
|
||||
.andReturn(requestBody);
|
||||
|
||||
ModelPrototype = mockConstructor(rawElement);
|
||||
ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
|
||||
|
||||
app.get('/foxx', function (providedReq) {
|
||||
called = (providedReq.parameters[paramName] instanceof ModelPrototype);
|
||||
}).bodyParam(paramName, description, ModelPrototype);
|
||||
|
||||
routes[0].action.callback(req, res);
|
||||
|
||||
assertTrue(called);
|
||||
ModelPrototype.assertIsSatisfied();
|
||||
},
|
||||
|
||||
testBodyParamWithMultipleElement: function () {
|
||||
var req = { parameters: {} },
|
||||
res = {},
|
||||
paramName = 'myBodyParam',
|
||||
description = stub(),
|
||||
rawElement = stub(),
|
||||
requestBody = { myBodyParam: [rawElement] },
|
||||
ModelPrototype = stub(),
|
||||
jsonSchemaId = stub(),
|
||||
called = false;
|
||||
|
||||
allow(req)
|
||||
.toReceive("body")
|
||||
.andReturn(requestBody);
|
||||
|
||||
ModelPrototype = mockConstructor(rawElement);
|
||||
ModelPrototype.toJSONSchema = function () { return { id: jsonSchemaId }; };
|
||||
|
||||
app.get('/foxx', function (providedReq) {
|
||||
called = (providedReq.parameters[paramName][0] instanceof ModelPrototype);
|
||||
}).bodyParam(paramName, description, [ModelPrototype]);
|
||||
|
||||
routes[0].action.callback(req, res);
|
||||
|
||||
assertTrue(called);
|
||||
ModelPrototype.assertIsSatisfied();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
jsunity.run(CreateFoxxControllerSpec);
|
||||
jsunity.run(SetRoutesFoxxControllerSpec);
|
||||
jsunity.run(DocumentationAndConstraintsSpec);
|
||||
jsunity.run(AddMiddlewareFoxxControllerSpec);
|
||||
jsunity.run(CommentDrivenDocumentationSpec);
|
||||
jsunity.run(HelperFunctionSpec);
|
||||
jsunity.run(SetupAuthorization);
|
||||
jsunity.run(FoxxControllerWithRootElement);
|
||||
|
||||
return jsunity.done();
|
||||
|
|
|
@ -295,6 +295,7 @@ ERROR_GRAPH_NOT_FOUND,1924,"graph not found","a graph with this name could not b
|
|||
ERROR_GRAPH_DUPLICATE,1925,"graph already exists","a graph with this name already exists.",
|
||||
ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST,1926,"collection does not exist"," does not exist.",
|
||||
ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX,1927,"not a vertex collection","the collection is not a vertex collection.",
|
||||
ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION,1928,"not in orphan collection","Vertex collection not in orphan collection of the graph.",
|
||||
|
||||
################################################################################
|
||||
## Session errors
|
||||
|
|
|
@ -211,6 +211,7 @@ void TRI_InitialiseErrorMessages (void) {
|
|||
REG_ERROR(ERROR_GRAPH_DUPLICATE, "graph already exists");
|
||||
REG_ERROR(ERROR_GRAPH_VERTEX_COL_DOES_NOT_EXIST, "collection does not exist");
|
||||
REG_ERROR(ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX, "not a vertex collection");
|
||||
REG_ERROR(ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION, "not in orphan collection");
|
||||
REG_ERROR(ERROR_SESSION_UNKNOWN, "unknown session");
|
||||
REG_ERROR(ERROR_SESSION_EXPIRED, "session expired");
|
||||
REG_ERROR(SIMPLE_CLIENT_UNKNOWN_ERROR, "unknown client error");
|
||||
|
|
|
@ -496,6 +496,8 @@ extern "C" {
|
|||
/// does not exist.
|
||||
/// - 1927: @LIT{not a vertex collection}
|
||||
/// the collection is not a vertex collection.
|
||||
/// - 1928: @LIT{not in orphan collection}
|
||||
/// Vertex collection not in orphan collection of the graph.
|
||||
/// - 1950: @LIT{unknown session}
|
||||
/// Will be raised when an invalid/unknown session id is passed to the server.
|
||||
/// - 1951: @LIT{session expired}
|
||||
|
@ -2626,6 +2628,16 @@ void TRI_InitialiseErrorMessages (void);
|
|||
|
||||
#define TRI_ERROR_GRAPH_WRONG_COLLECTION_TYPE_VERTEX (1927)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1928: ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION
|
||||
///
|
||||
/// not in orphan collection
|
||||
///
|
||||
/// Vertex collection not in orphan collection of the graph.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define TRI_ERROR_GRAPH_NOT_IN_ORPHAN_COLLECTION (1928)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/// @brief 1950: ERROR_SESSION_UNKNOWN
|
||||
///
|
||||
|
|
Loading…
Reference in New Issue