mirror of https://gitee.com/bigwinds/arangodb
Merge branch 'devel' of github.com:arangodb/arangodb into devel
This commit is contained in:
commit
c46ff5c085
|
@ -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)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
|
@ -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.
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Reference in New Issue