1
0
Fork 0

Merge branch 'devel' of github.com:arangodb/arangodb into devel

This commit is contained in:
Michael Hackstein 2016-07-12 18:07:21 +02:00
commit c46ff5c085
11 changed files with 124 additions and 25 deletions

View File

@ -23,6 +23,9 @@ devel
* When disabling Foxx development mode the setup script is now re-run * When disabling Foxx development mode the setup script is now re-run
* Foxx now provides an easy way to directly serve GraphQL requests using the
`@arangodb/foxx/graphql` module and the bundled `graphql-sync` dependency
v3.0.3 (XXXX-XX-XX) v3.0.3 (XXXX-XX-XX)
------------------- -------------------

View File

@ -0,0 +1,105 @@
!CHAPTER Using GraphQL in Foxx
`const createGraphQLRouter = require('@arangodb/foxx/graphql');`
Foxx bundles the [`graphql-sync` module](https://github.com/arangodb/graphql-sync), which is a synchronous wrapper for the official JavaScript GraphQL reference implementation, to allow writing GraphQL schemas directly inside Foxx.
Additionally the `@arangodb/foxx/graphql` lets you create routers for serving GraphQL requests, which closely mimicks the behaviour of the [`express-graphql` module](https://github.com/graphql/express-graphql).
For more information on `graphql-sync` see the [`graphql-js` API reference](http://graphql.org/docs/api-reference-graphql/) (note that `graphql-sync` always uses raw values instead of wrapping them in promises).
For an example of a GraphQL schema in Foxx that resolves fields using the database see [the GraphQL example service](https://github.com/arangodb-foxx/demo-graphql) (also available from the Foxx store).
**Examples**
```js
const graphql = require('graphql-sync');
const graphqlSchema = new graphql.GraphQLSchema({
// ...
});
// Mounting a graphql endpoint directly in a service:
module.context.use('/graphql', createGraphQLRouter({
schema: graphqlSchema,
graphiql: true
}));
// Or at the service's root URL:
module.context.use(createGraphQLRouter({
schema: graphqlSchema,
graphiql: true
}));
// Or inside an existing router:
router.get('/hello', function (req, res) {
res.write('Hello world!');
});
router.use('/graphql', createGraphQLRouter({
schema: graphqlSchema,
graphiql: true
}));
```
!SECTION Creating a router
`createGraphQLRouter(options): Router`
This returns a new router object with POST and GET routes for serving GraphQL requests.
**Arguments**
* **options**: `object`
An object with any of the following properties:
* **schema**: `GraphQLSchema`
A GraphQL Schema object from `graphql-sync`.
* **context**: `any` (optional)
The GraphQL context that will be passed to the `graphql()` function from `graphql-sync` to handle GraphQL queries.
* **rootValue**: `object` (optional)
The GraphQL root value that will be passed to the `graphql()` function from `graphql-sync` to handle GraphQL queries.
* **pretty**: `boolean` (Default: `false`)
If `true`, JSON responses will be pretty-printed.
* **formatError**: `Function` (optional)
A function that will be used to format errors produced by `graphql-sync`. If omitted, the `formatError` function from `graphql-sync` will be used instead.
* **validationRules**: `Array<any>` (optional)
Additional validation rules queries must satisfy in addition to those defined in the GraphQL spec.
* **graphiql**: `boolean` (Default: `false`)
If `true`, the [GraphiQL](https://github.com/graphql/graphiql) explorer will be served when loaded directly from a browser.
If a GraphQL Schema object is passed instead of an options object it will be interpreted as the *schema* option.
!SECTION Generated routes
The router handles GET and POST requests to its root path and accepts the following parameters, which can be provided either as query parameters or as the POST request body:
* **query**: `string`
A GraphQL query that will be executed.
* **variables**: `object | string` (optional)
An object or a string containing a JSON object with runtime values to use for any GraphQL query variables.
* **operationName**: `string` (optional)
If the provided `query` contains multiple named operations, this specifies which operation should be executed.
* **raw**: `boolean` (Default: `false`)
Forces a JSON response even if *graphiql* is enabled and the request was made using a browser.
The POST request body can be provided as JSON or as query string using `application/x-www-form-urlencoded`. A request body passed as `application/graphql` will be interpreted as the `query` parameter.

View File

@ -74,6 +74,7 @@
* [Middleware](Foxx/Router/Middleware.md) * [Middleware](Foxx/Router/Middleware.md)
* [Request](Foxx/Router/Request.md) * [Request](Foxx/Router/Request.md)
* [Response](Foxx/Router/Response.md) * [Response](Foxx/Router/Response.md)
* [Using GraphQL](Foxx/GraphQL.md)
* [Sessions middleware](Foxx/Sessions/README.md) * [Sessions middleware](Foxx/Sessions/README.md)
* [Session storages](Foxx/Sessions/Storages/README.md) * [Session storages](Foxx/Sessions/Storages/README.md)
* [Collection storage](Foxx/Sessions/Storages/Collection.md) * [Collection storage](Foxx/Sessions/Storages/Collection.md)

View File

@ -254,7 +254,6 @@ bool SkiplistLookupBuilder::next() {
return false; return false;
} }
SkiplistInLookupBuilder::SkiplistInLookupBuilder( SkiplistInLookupBuilder::SkiplistInLookupBuilder(
Transaction* trx, Transaction* trx,
std::vector<std::vector<arangodb::aql::AstNode const*>>& ops, std::vector<std::vector<arangodb::aql::AstNode const*>>& ops,
@ -533,7 +532,6 @@ TRI_doc_mptr_t* SkiplistIterator::next() {
return tmp->document()->document(); return tmp->document()->document();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Checks if the interval is valid. It is declared invalid if /// @brief Checks if the interval is valid. It is declared invalid if
/// one border is nullptr or the right is lower than left. /// one border is nullptr or the right is lower than left.
@ -557,14 +555,12 @@ bool SkiplistIterator2::intervalValid(Node* left, Node* right) const {
return true; return true;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief Reset the cursor /// @brief Reset the cursor
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void SkiplistIterator2::reset() { void SkiplistIterator2::reset() {
// If _interals is empty at this point // If _intervals is empty at this point
// the cursor does not contain any // the cursor does not contain any
// document at all. Reset is pointless // document at all. Reset is pointless
if (!_intervals.empty()) { if (!_intervals.empty()) {
@ -690,7 +686,6 @@ void SkiplistIterator2::initNextInterval() {
} }
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief create the skiplist index /// @brief create the skiplist index
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

@ -60,7 +60,7 @@ class BaseSkiplistLookupBuilder {
arangodb::velocypack::Slice _upperSlice; arangodb::velocypack::Slice _upperSlice;
public: public:
BaseSkiplistLookupBuilder(Transaction* trx) : explicit BaseSkiplistLookupBuilder(Transaction* trx) :
_lowerBuilder(trx), _upperBuilder(trx) _lowerBuilder(trx), _upperBuilder(trx)
{ {
_isEquality = true; _isEquality = true;

View File

@ -2238,7 +2238,6 @@ int RestReplicationHandler::processRestoreDataBatch(
// Now try to insert all keys for which the last marker was a document // Now try to insert all keys for which the last marker was a document
// marker, note that these could still be replace markers! // marker, note that these could still be replace markers!
std::vector<VPackValueLength> insertTried;
builder.clear(); builder.clear();
{ {
VPackArrayBuilder guard(&builder); VPackArrayBuilder guard(&builder);

View File

@ -279,7 +279,7 @@ int TraditionalKeyGenerator::validate(std::string const& key, bool isRestore) {
/// @brief track usage of a key /// @brief track usage of a key
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void TraditionalKeyGenerator::track(std::string const&) {} void TraditionalKeyGenerator::track(char const*, VPackValueLength) {}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @brief create a VPack representation of the generator /// @brief create a VPack representation of the generator
@ -398,9 +398,9 @@ int AutoIncrementKeyGenerator::validate(std::string const& key,
/// @brief track usage of a key /// @brief track usage of a key
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void AutoIncrementKeyGenerator::track(std::string const& key) { void AutoIncrementKeyGenerator::track(char const* p, VPackValueLength length) {
// check the numeric key part // check the numeric key part
uint64_t value = StringUtils::uint64(key); uint64_t value = StringUtils::uint64(p, length);
if (value > _lastValue) { if (value > _lastValue) {
// and update our last value // and update our last value

View File

@ -104,7 +104,7 @@ class KeyGenerator {
/// @brief track usage of a key /// @brief track usage of a key
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
virtual void track(std::string const&) = 0; virtual void track(char const*, VPackValueLength) = 0;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief return a VelocyPack representation of the generator /// @brief return a VelocyPack representation of the generator
@ -176,7 +176,7 @@ class TraditionalKeyGenerator : public KeyGenerator {
/// @brief track usage of a key /// @brief track usage of a key
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void track(std::string const&) override; void track(char const*, VPackValueLength) override final;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief return the generator name (must be lowercase) /// @brief return the generator name (must be lowercase)
@ -229,7 +229,7 @@ class AutoIncrementKeyGenerator : public KeyGenerator {
/// @brief track usage of a key /// @brief track usage of a key
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
void track(std::string const&) override; void track(char const*, VPackValueLength) override final;
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
/// @brief return the generator name (must be lowercase) /// @brief return the generator name (must be lowercase)

View File

@ -276,7 +276,7 @@ class Traverser {
/// @brief Constructor. This is an abstract only class. /// @brief Constructor. This is an abstract only class.
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
Traverser(TraverserOptions& opts) explicit Traverser(TraverserOptions& opts)
: _readDocuments(0), : _readDocuments(0),
_filteredPaths(0), _filteredPaths(0),
_pruneNext(false), _pruneNext(false),

View File

@ -793,7 +793,9 @@ static int OpenIteratorHandleDocumentMarker(TRI_df_marker_t const* marker,
Transaction::extractKeyAndRevFromDocument(slice, keySlice, revisionId); Transaction::extractKeyAndRevFromDocument(slice, keySlice, revisionId);
SetRevision(document, revisionId, false); SetRevision(document, revisionId, false);
document->_keyGenerator->track(keySlice.copyString()); VPackValueLength length;
char const* p = keySlice.getString(length);
document->_keyGenerator->track(p, length);
++state->_documents; ++state->_documents;
@ -890,7 +892,9 @@ static int OpenIteratorHandleDeletionMarker(TRI_df_marker_t const* marker,
Transaction::extractKeyAndRevFromDocument(slice, keySlice, revisionId); Transaction::extractKeyAndRevFromDocument(slice, keySlice, revisionId);
document->setLastRevision(revisionId, false); document->setLastRevision(revisionId, false);
document->_keyGenerator->track(keySlice.copyString()); VPackValueLength length;
char const* p = keySlice.getString(length);
document->_keyGenerator->track(p, length);
++state->_deletions; ++state->_deletions;

View File

@ -22,14 +22,6 @@
// / @author Alan Plum // / @author Alan Plum
// ////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////
// * schema: Object the schema
// * context: ?mixed graphql context
// * rootValue: ?Object graphql rootValue
// * pretty: ?boolean prettier output
// * formatError: ?Function formatError for graphql errors
// * validationRules: ?Array<any> additional validation rules???
// * graphiql: ?boolean enable graphiql
const dd = require('dedent'); const dd = require('dedent');
const assert = require('assert'); const assert = require('assert');
const joi = require('joi'); const joi = require('joi');