1
0
Fork 0
arangodb/arangod/RestHandler/RestSimpleQueryHandler.cpp

274 lines
9.5 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief simple query handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 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 ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2010-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#include "RestSimpleQueryHandler.h"
#include "Aql/Query.h"
#include "Aql/QueryRegistry.h"
#include "Basics/Exceptions.h"
#include "Basics/json.h"
#include "Basics/MutexLocker.h"
#include "Basics/ScopeGuard.h"
#include "Utils/Cursor.h"
#include "Utils/CursorRepository.h"
#include "V8Server/ApplicationV8.h"
using namespace triagens::arango;
using namespace triagens::rest;
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////
RestSimpleQueryHandler::RestSimpleQueryHandler (HttpRequest* request,
std::pair<triagens::arango::ApplicationV8*, triagens::aql::QueryRegistry*>* pair)
: RestCursorHandler(request, pair) {
}
// -----------------------------------------------------------------------------
// --SECTION-- Handler methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
HttpHandler::status_t RestSimpleQueryHandler::execute () {
// extract the sub-request type
HttpRequest::HttpRequestType type = _request->requestType();
if (type == HttpRequest::HTTP_REQUEST_PUT) {
char const* prefix = _request->requestPath();
if (strcmp(prefix, RestVocbaseBaseHandler::SIMPLE_QUERY_ALL_PATH.c_str()) == 0) {
// all query
allDocuments();
return status_t(HANDLER_DONE);
}
}
generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);
return status_t(HANDLER_DONE);
}
// -----------------------------------------------------------------------------
// --SECTION-- private methods
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_put_api_simple_all
/// @brief returns all documents of a collection
///
/// @RESTHEADER{PUT /_api/simple/all, Return all documents}
///
/// @RESTBODYPARAM{query,string,required}
/// Contains the query.
///
/// @RESTDESCRIPTION
///
/// Returns all documents of a collections. The call expects a JSON object
/// as body with the following attributes:
///
/// - *collection*: The name of the collection to query.
///
/// - *skip*: The number of documents to skip in the query (optional).
///
/// - *limit*: The maximal amount of documents to return. The *skip*
/// is applied before the *limit* restriction. (optional)
///
/// Returns a cursor containing the result, see [Http Cursor](../HttpAqlQueryCursor/README.md) for details.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{201}
/// is returned if the query was executed successfully.
///
/// @RESTRETURNCODE{400}
/// is returned if the body does not contain a valid JSON representation of a
/// query. The response body contains an error document in this case.
///
/// @RESTRETURNCODE{404}
/// is returned if the collection specified by *collection* is unknown. The
/// response body contains an error document in this case.
///
/// @EXAMPLES
///
/// Limit the amount of documents using *limit*
///
/// @EXAMPLE_ARANGOSH_RUN{RestSimpleAllSkipLimit}
/// var cn = "products";
/// db._drop(cn);
/// var collection = db._create(cn);
/// collection.save({"Hello1" : "World1" });
/// collection.save({"Hello2" : "World2" });
/// collection.save({"Hello3" : "World3" });
/// collection.save({"Hello4" : "World4" });
/// collection.save({"Hello5" : "World5" });
///
/// var url = "/_api/simple/all";
/// var body = '{ "collection": "products", "skip": 2, "limit" : 2 }';
///
/// var response = logCurlRequest('PUT', url, body);
///
/// assert(response.code === 201);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// Using a *batchSize* value
///
/// @EXAMPLE_ARANGOSH_RUN{RestSimpleAllBatch}
/// var cn = "products";
/// db._drop(cn);
/// var collection = db._create(cn);
/// collection.save({"Hello1" : "World1" });
/// collection.save({"Hello2" : "World2" });
/// collection.save({"Hello3" : "World3" });
/// collection.save({"Hello4" : "World4" });
/// collection.save({"Hello5" : "World5" });
///
/// var url = "/_api/simple/all";
/// var body = '{ "collection": "products", "batchSize" : 3 }';
///
/// var response = logCurlRequest('PUT', url, body);
///
/// assert(response.code === 201);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
void RestSimpleQueryHandler::allDocuments () {
try {
std::unique_ptr<TRI_json_t> json(parseJsonBody());
if (json.get() == nullptr) {
return;
}
auto const value = TRI_LookupObjectJson(json.get(), "collection");
if (! TRI_IsStringJson(value)) {
generateError(HttpResponse::BAD, TRI_ERROR_TYPE_ERROR, "expecting string for <collection>");
return;
}
std::string collectionName = std::string(value->_value._string.data, value->_value._string.length - 1);
if (! collectionName.empty()) {
auto const* col = TRI_LookupCollectionByNameVocBase(_vocbase, collectionName.c_str());
if (col != nullptr && collectionName.compare(col->_name) != 0) {
// user has probably passed in a numeric collection id.
// translate it into a "real" collection name
collectionName = std::string(col->_name);
}
}
triagens::basics::Json bindVars(triagens::basics::Json::Object, 3);
bindVars("@collection", triagens::basics::Json(collectionName));
std::string aql("FOR doc IN @@collection ");
auto const skip = TRI_LookupObjectJson(json.get(), "skip");
auto const limit = TRI_LookupObjectJson(json.get(), "limit");
if (TRI_IsNumberJson(skip) || TRI_IsNumberJson(limit)) {
aql.append("LIMIT @skip, @limit ");
if (TRI_IsNumberJson(skip)) {
bindVars("skip", triagens::basics::Json(skip->_value._number));
}
else {
bindVars("skip", triagens::basics::Json(triagens::basics::Json::Null));
}
if (TRI_IsNumberJson(limit)) {
bindVars("limit", triagens::basics::Json(limit->_value._number));
}
else {
bindVars("limit", triagens::basics::Json(triagens::basics::Json::Null));
}
}
aql.append("RETURN doc");
triagens::basics::Json data(triagens::basics::Json::Object, 5);
data("query", triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, aql));
data("bindVars", bindVars);
data("count", triagens::basics::Json(true));
// pass on standard options
{
auto value = TRI_LookupObjectJson(json.get(), "ttl");
if (value != nullptr) {
data("ttl", triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, value)));
}
value = TRI_LookupObjectJson(json.get(), "batchSize");
if (value != nullptr) {
data("batchSize", triagens::basics::Json(TRI_UNKNOWN_MEM_ZONE, TRI_CopyJson(TRI_UNKNOWN_MEM_ZONE, value)));
}
}
// now run the actual query and handle the result
processQuery(data.json());
}
catch (triagens::basics::Exception const& ex) {
generateError(HttpResponse::responseCode(ex.code()), ex.code(), ex.what());
}
catch (std::bad_alloc const&) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);
}
catch (std::exception const& ex) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, ex.what());
}
catch (...) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL);
}
}
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End: