1
0
Fork 0
arangodb/js/actions/_api/collection/app.js

1811 lines
61 KiB
JavaScript

/*jshint strict: false */
////////////////////////////////////////////////////////////////////////////////
/// @brief querying and managing collections
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB 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 Achim Brandt
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var arangodb = require("@arangodb");
var actions = require("@arangodb/actions");
var cluster = require("@arangodb/cluster");
// -----------------------------------------------------------------------------
// --SECTION-- private functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief return a prefixed URL
////////////////////////////////////////////////////////////////////////////////
function databasePrefix (req, url) {
if (req.hasOwnProperty('compatibility') && req.compatibility < 10400) {
// pre 1.4-style location response (e.g. /_api/collection/xyz)
return url;
}
// 1.4-style location response (e.g. /_db/dbname/_api/collection/xyz)
return "/_db/" + encodeURIComponent(arangodb.db._name()) + url;
}
////////////////////////////////////////////////////////////////////////////////
/// @brief collection representation
////////////////////////////////////////////////////////////////////////////////
function collectionRepresentation (collection, showProperties, showCount, showFigures) {
var result = {};
result.id = collection._id;
result.name = collection.name();
result.isSystem = (result.name.charAt(0) === '_');
if (showProperties) {
var properties = collection.properties();
result.doCompact = properties.doCompact;
result.isVolatile = properties.isVolatile;
result.journalSize = properties.journalSize;
result.keyOptions = properties.keyOptions;
result.waitForSync = properties.waitForSync;
result.indexBuckets = properties.indexBuckets;
if (cluster.isCoordinator()) {
result.shardKeys = properties.shardKeys;
result.numberOfShards = properties.numberOfShards;
}
}
if (showCount) {
result.count = collection.count();
}
if (showFigures) {
var figures = collection.figures();
if (figures) {
result.figures = figures;
}
}
result.status = collection.status();
result.type = collection.type();
return result;
}
// -----------------------------------------------------------------------------
// --SECTION-- public functions
// -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @brief helper to parse arguments for creating collections
////////////////////////////////////////////////////////////////////////////////
function parseBodyForCreateCollection (req, res) {
var body = actions.getJsonBody(req, res);
if (body === undefined) {
return { bodyIsEmpty: true };
}
var r = {};
if (! body.hasOwnProperty("name")) {
r.name = "";
}
else {
r.name = body.name;
}
r.parameters = { waitForSync : false };
r.type = arangodb.ArangoCollection.TYPE_DOCUMENT;
if (body.hasOwnProperty("doCompact")) {
r.parameters.doCompact = body.doCompact;
}
if (body.hasOwnProperty("isSystem")) {
r.parameters.isSystem = (body.isSystem && r.name[0] === '_');
}
if (body.hasOwnProperty("id")) {
r.parameters.id = body.id;
}
if (body.hasOwnProperty("isVolatile")) {
r.parameters.isVolatile = body.isVolatile;
}
if (body.hasOwnProperty("journalSize")) {
r.parameters.journalSize = body.journalSize;
}
if (body.hasOwnProperty("indexBuckets")) {
r.parameters.indexBuckets = body.indexBuckets;
}
if (body.hasOwnProperty("keyOptions")) {
r.parameters.keyOptions = body.keyOptions;
}
if (body.hasOwnProperty("type")) {
r.type = body.type;
}
if (body.hasOwnProperty("waitForSync")) {
r.parameters.waitForSync = body.waitForSync;
}
if (body.hasOwnProperty("shardKeys") && cluster.isCoordinator()) {
r.parameters.shardKeys = body.shardKeys || { };
}
if (body.hasOwnProperty("numberOfShards") && cluster.isCoordinator()) {
r.parameters.numberOfShards = body.numberOfShards || 0;
}
if (body.hasOwnProperty("distributeShardsLike") && cluster.isCoordinator()) {
r.parameters.distributeShardsLike = body.distributeShardsLike || "";
}
return r;
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_post_api_collection
/// @brief creates a collection
///
/// @RESTHEADER{POST /_api/collection, Create collection}
///
/// @RESTBODYPARAM{name,string,required,string}
/// The name of the collection.
///
/// @RESTBODYPARAM{waitForSync,boolean,optional,}
/// If *true* then the data is synchronized to disk before returning from a
/// document create, update, replace or removal operation. (default: false)
///
/// @RESTBODYPARAM{doCompact,boolean,optional,}
/// whether or not the collection will be compacted (default is *true*)
///
/// @RESTBODYPARAM{journalSize,integer,optional,int64}
/// The maximal size of a journal or datafile in bytes. The value
/// must be at least `1048576` (1 MiB). (The default is a configuration parameter)
///
/// @RESTBODYPARAM{isSystem,boolean,optional,}
/// If *true*, create a system collection. In this case *collection-name*
/// should start with an underscore. End users should normally create non-system
/// collections only. API implementors may be required to create system
/// collections in very special occasions, but normally a regular collection will do.
/// (The default is *false*)
///
/// @RESTBODYPARAM{isVolatile,boolean,optional,}
/// If *true* then the collection data is kept in-memory only and not made persistent.
/// Unloading the collection will cause the collection data to be discarded. Stopping
/// or re-starting the server will also cause full loss of data in the
/// collection. Setting this option will make the resulting collection be
/// slightly faster than regular collections because ArangoDB does not
/// enforce any synchronization to disk and does not calculate any CRC
/// checksums for datafiles (as there are no datafiles). This option
/// should therefore be used for cache-type collections only, and not
/// for data that cannot be re-created otherwise.
/// (The default is *false*)
///
/// @RESTBODYPARAM{keyOptions,object,optional,JSF_post_api_collection_opts}
/// additional options for key generation. If specified, then *keyOptions*
/// should be a JSON array containing the following attributes:
///
/// @RESTSTRUCT{type,JSF_post_api_collection_opts,string,required,string}
/// specifies the type of the key generator. The currently available generators are
/// *traditional* and *autoincrement*.
///
/// @RESTSTRUCT{allowUserKeys,JSF_post_api_collection_opts,boolean,required,}
/// if set to *true*, then it is allowed to supply own key values in the
/// *_key* attribute of a document. If set to *false*, then the key generator
/// will solely be responsible for generating keys and supplying own key values
/// in the *_key* attribute of documents is considered an error.
///
/// @RESTSTRUCT{increment,JSF_post_api_collection_opts,integer,required,int64}
/// increment value for *autoincrement* key generator. Not used for other key
/// generator types.
///
/// @RESTSTRUCT{offset,JSF_post_api_collection_opts,integer,required,int64}
/// Initial offset value for *autoincrement* key generator.
/// Not used for other key generator types.
///
/// @RESTBODYPARAM{type,integer,optional,int64}
/// (The default is *2*): the type of the collection to create.
/// The following values for *type* are valid:
///
/// - *2*: document collection
/// - *3*: edges collection
///
/// @RESTBODYPARAM{indexBuckets,integer,optional,int64}
/// The: number of buckets into which indexes using a hash
/// table are split. The default is 16 and this number has to be a
/// power of 2 and less than or equal to 1024.
///
/// For very large collections one should increase this to avoid long pauses
/// when the hash table has to be initially built or resized, since buckets
/// are resized individually and can be initially built in parallel. For
/// example, 64 might be a sensible value for a collection with 100
/// 000 000 documents. Currently, only the edge index respects this
/// value, but other index types might follow in future ArangoDB versions.
/// Changes (see below) are applied when the collection is loaded the next
/// time.
///
/// @RESTBODYPARAM{numberOfShards,integer,optional,int64}
/// (The default is *1*): in a cluster, this value determines the
/// number of shards to create for the collection. In a single
/// server setup, this option is meaningless.
///
/// @RESTBODYPARAM{shardKeys,string,optional,string}
/// (The default is *[ "_key" ]*): in a cluster, this attribute determines
/// which document attributes are used to determine the target shard for documents.
/// Documents are sent to shards based on the values of their shard key attributes.
/// The values of all shard key attributes in a document are hashed,
/// and the hash value is used to determine the target shard.
/// **Note**: Values of shard key attributes cannot be changed once set.
/// This option is meaningless in a single server setup.
///
/// @RESTDESCRIPTION
/// Creates an new collection with a given name. The request must contain an
/// object with the following attributes.
///
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404* is returned.
///
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionCreateCollection}
/// var url = "/_api/collection";
/// var body = {
/// name: "testCollectionBasics"
/// };
///
/// var response = logCurlRequest('POST', url, body);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// body = {
/// name: "testCollectionEdges",
/// type : 3
/// };
///
/// var response = logCurlRequest('POST', url, body);
///
/// assert(response.code === 200);
/// logJsonResponse(response);
///
/// db._flushCache();
/// db._drop("testCollectionBasics");
/// db._drop("testCollectionEdges");
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionCreateKeyopt}
/// var url = "/_api/collection";
/// var body = {
/// name: "testCollectionUsers",
/// keyOptions : {
/// type : "autoincrement",
/// increment : 5,
/// allowUserKeys : true
/// }
/// };
///
/// var response = logCurlRequest('POST', url, body);
///
/// assert(response.code === 200);
/// logJsonResponse(response);
///
/// db._flushCache();
/// db._drop("testCollectionUsers");
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function post_api_collection (req, res) {
var r = parseBodyForCreateCollection(req, res);
if (r.bodyIsEmpty) {
return; // error in JSON, is already reported
}
if (r.name === "") {
actions.resultBad(req, res, arangodb.ERROR_ARANGO_ILLEGAL_NAME,
"name must be non-empty");
return;
}
try {
var collection;
if (typeof(r.type) === "string") {
if (r.type.toLowerCase() === "edge" || r.type === "3") {
r.type = arangodb.ArangoCollection.TYPE_EDGE;
}
}
if (r.type === arangodb.ArangoCollection.TYPE_EDGE) {
collection = arangodb.db._createEdgeCollection(r.name, r.parameters);
}
else {
collection = arangodb.db._createDocumentCollection(r.name, r.parameters);
}
var result = {};
result.id = collection._id;
result.name = collection.name();
result.waitForSync = r.parameters.waitForSync || false;
result.isVolatile = r.parameters.isVolatile || false;
result.isSystem = r.parameters.isSystem || false;
result.status = collection.status();
result.type = collection.type();
result.keyOptions = collection.keyOptions;
if (cluster.isCoordinator()) {
result.shardKeys = collection.shardKeys;
result.numberOfShards = collection.numberOfShards;
result.distributeShardsLike = collection.distributeShardsLike || "";
}
var headers = {
location: databasePrefix(req, "/_api/collection/" + result.name)
};
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_get_api_collections
/// @brief returns all collections
///
/// @RESTHEADER{GET /_api/collection,reads all collections}
///
/// @RESTQUERYPARAMETERS
///
/// @RESTQUERYPARAM{excludeSystem,boolean,optional}
/// Whether or not system collections should be excluded from the result.
///
/// @RESTDESCRIPTION
/// Returns an object with an attribute *collections* containing an
/// array of all collection descriptions. The same information is also
/// available in the *names* as an object with the collection names
/// as keys.
///
/// By providing the optional query parameter *excludeSystem* with a value of
/// *true*, all system collections will be excluded from the response.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// The list of collections
///
/// @EXAMPLES
///
/// Return information about all collections:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetAllCollections}
/// var url = "/_api/collection";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function get_api_collections (req, res) {
var i;
var list = [];
var names = {};
var excludeSystem;
var collections = arangodb.db._collections();
excludeSystem = false;
if (req.parameters.hasOwnProperty('excludeSystem')) {
var value = req.parameters.excludeSystem.toLowerCase();
if (value === 'true' || value === 'yes' || value === 'on' || value === 'y' || value === '1') {
excludeSystem = true;
}
}
for (i = 0; i < collections.length; ++i) {
var collection = collections[i];
var rep = collectionRepresentation(collection);
// include system collections or exclude them?
if (! excludeSystem || rep.name.substr(0, 1) !== '_') {
list.push(rep);
names[rep.name] = rep;
}
}
var result = { collections : list, names : names };
actions.resultOk(req, res, actions.HTTP_OK, result);
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_get_api_collection_name
/// @brief returns a collection
///
/// @RESTHEADER{GET /_api/collection/{collection-name}, Return information about a collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// The result is an object describing the collection with the following
/// attributes:
///
/// - *id*: The identifier of the collection.
///
/// - *name*: The name of the collection.
///
/// - *status*: The status of the collection as number.
/// - 1: new born collection
/// - 2: unloaded
/// - 3: loaded
/// - 4: in the process of being unloaded
/// - 5: deleted
/// - 6: loading
///
/// Every other status indicates a corrupted collection.
///
/// - *type*: The type of the collection as number.
/// - 2: document collection (normal case)
/// - 3: edges collection
///
/// - *isSystem*: If *true* then the collection is a system collection.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404* is
/// returned.
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_get_api_collection_properties
/// @brief reads the properties of the specified collection
///
/// @RESTHEADER{GET /_api/collection/{collection-name}/properties, Read properties of a collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// In addition to the above, the result will always contain the
/// *waitForSync*, *doCompact*, *journalSize*, and *isVolatile* attributes.
/// This is achieved by forcing a load of the underlying collection.
///
/// - *waitForSync*: If *true* then creating, changing or removing
/// documents will wait until the data has been synchronized to disk.
///
/// - *doCompact*: Whether or not the collection will be compacted.
///
/// - *journalSize*: The maximal size setting for journals / datafiles
/// in bytes.
///
/// - *keyOptions*: JSON object which contains key generation options:
/// - *type*: specifies the type of the key generator. The currently
/// available generators are *traditional* and *autoincrement*.
/// - *allowUserKeys*: if set to *true*, then it is allowed to supply
/// own key values in the *_key* attribute of a document. If set to
/// *false*, then the key generator is solely responsible for
/// generating keys and supplying own key values in the *_key* attribute
/// of documents is considered an error.
///
/// - *isVolatile*: If *true* then the collection data will be
/// kept in memory only and ArangoDB will not write or sync the data
/// to disk.
///
/// In a cluster setup, the result will also contain the following attributes:
/// - *numberOfShards*: the number of shards of the collection.
///
/// - *shardKeys*: contains the names of document attributes that are used to
/// determine the target shard for documents.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// Using an identifier:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionIdentifier}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/"+ coll._id + "/properties";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// ~ db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// Using a name:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionName}
/// var cn = "products";
/// db._drop(cn);
/// db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/products/properties";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_get_api_collection_count
/// @brief Counts the documents in a collection
///
/// @RESTHEADER{GET /_api/collection/{collection-name}/count, Return number of documents in a collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// In addition to the above, the result also contains the number of documents.
/// **Note** that this will always load the collection into memory.
///
/// - *count*: The number of documents inside the collection.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// Requesting the number of documents:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionCount}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: true });
/// for(var i=0;i<100;i++) {
/// coll.save({"count" : i });
/// }
/// var url = "/_api/collection/"+ coll.name() + "/count";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_get_api_collection_figures
/// @brief Fetch the statistics of a collection
///
/// @RESTHEADER{GET /_api/collection/{collection-name}/figures, Return statistics for a collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// In addition to the above, the result also contains the number of documents
/// and additional statistical information about the collection.
/// **Note** : This will always load the collection into memory.
///
/// **Note**: collection data that are stored in the write-ahead log only are
/// not reported in the results. When the write-ahead log is collected, documents
/// might be added to journals and datafiles of the collection, which may modify
/// the figures of the collection.
///
/// Additionally, the filesizes of collection and index parameter JSON files are
/// not reported. These files should normally have a size of a few bytes
/// each. Please also note that the *fileSize* values are reported in bytes
/// and reflect the logical file sizes. Some filesystems may use optimisations
/// (e.g. sparse files) so that the actual physical file size is somewhat
/// different. Directories and sub-directories may also require space in the
/// file system, but this space is not reported in the *fileSize* results.
///
/// That means that the figures reported do not reflect the actual disk
/// usage of the collection with 100% accuracy. The actual disk usage of
/// a collection is normally slightly higher than the sum of the reported
/// *fileSize* values. Still the sum of the *fileSize* values can still be
/// used as a lower bound approximation of the disk usage.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{200}
/// Returns information about the collection:
///
/// @RESTREPLYBODY{count,integer,required,int64}
/// The number of documents currently present in the collection.
///
/// @RESTREPLYBODY{figures,object,required,collection_figures}
/// metrics of the collection
///
/// @RESTSTRUCT{alive,collection_figures,object,required,collection_figures_alive}
/// the currently active figures
///
/// @RESTSTRUCT{count,collection_figures_alive,integer,required,int64}
/// The number of currently active documents in all datafiles
/// and journals of the collection. Documents that are contained in the
/// write-ahead log only are not reported in this figure.
///
/// @RESTSTRUCT{size,collection_figures_alive,integer,required,int64}
/// The total size in bytes used by all active documents of
/// the collection. Documents that are contained in the write-ahead log only are
/// not reported in this figure.
///
/// @RESTSTRUCT{dead,collection_figures,object,required,collection_figures_dead}
/// the items waiting to be swept away by the cleaner
///
/// @RESTSTRUCT{count,collection_figures_dead,integer,required,int64}
/// The number of dead documents. This includes document
/// versions that have been deleted or replaced by a newer version. Documents
/// deleted or replaced that are contained the write-ahead log only are not reported
/// in this figure.
///
/// @RESTSTRUCT{size,collection_figures_dead,integer,required,int64}
/// The total size in bytes used by all dead documents.
///
/// @RESTSTRUCT{deletion,collection_figures_dead,integer,required,int64}
/// The total number of deletion markers. Deletion markers
/// only contained in the write-ahead log are not reporting in this figure.
///
/// @RESTSTRUCT{datafiles,collection_figures,object,required,collection_figures_datafiles}
/// Metrics regarding the datafiles
///
/// @RESTSTRUCT{count,collection_figures_datafiles,integer,required,int64}
/// The number of datafiles.
///
/// @RESTSTRUCT{fileSize,collection_figures_datafiles,integer,required,int64}
/// The total filesize of datafiles (in bytes).
///
/// @RESTSTRUCT{journals,collection_figures,object,required,collection_figures_journals}
/// Metrics regarding the journal files
///
/// @RESTSTRUCT{count,collection_figures_journals,integer,required,int64}
/// The number of journal files.
///
/// @RESTSTRUCT{fileSize,collection_figures_journals,integer,required,int64}
/// The total filesize of all journal files (in bytes).
///
/// @RESTSTRUCT{compactors,collection_figures,object,required,collection_figures_compactors}
///
/// @RESTSTRUCT{count,collection_figures_compactors,integer,required,int64}
/// The number of compactor files.
///
/// @RESTSTRUCT{fileSize,collection_figures_compactors,integer,required,int64}
/// The total filesize of all compactor files (in bytes).
///
/// @RESTSTRUCT{shapefiles,collection_figures,object,required,collection_figures_shapefiles}
/// **deprecated**
///
/// @RESTSTRUCT{count,collection_figures_shapefiles,integer,required,int64}
/// The number of shape files. This value is deprecated and kept for compatibility reasons only.
/// The value will always be 0 since ArangoDB 2.0 and higher.
///
/// @RESTSTRUCT{fileSize,collection_figures_shapefiles,integer,required,int64}
/// The total filesize of the shape files. This value is deprecated and kept
/// for compatibility reasons only. The value will always be 0 in ArangoDB 2.0 and higher.
///
/// @RESTSTRUCT{shapes,collection_figures,object,required,collection_figures_shapes}
/// @RESTSTRUCT{count,collection_figures_shapes,integer,required,int64}
/// The total number of shapes used in the collection. This includes shapes
/// that are not in use anymore. Shapes that are contained
/// in the write-ahead log only are not reported in this figure.
///
/// @RESTSTRUCT{size,collection_figures_shapes,integer,required,int64}
/// The total size of all shapes (in bytes). This includes
/// shapes that are not in use anymore. Shapes that are contained in the
/// write-ahead log only are not reported in this figure.
///
/// @RESTSTRUCT{attributes,collection_figures,object,required,collection_figures_attributes}
/// @RESTSTRUCT{count,collection_figures_attributes,integer,required,int64}
/// The total number of attributes used in the
/// collection. Note: the value includes data of attributes that are not in use
/// anymore. Attributes that are contained in the write-ahead log only are
/// not reported in this figure.
///
/// @RESTSTRUCT{size,collection_figures_attributes,integer,required,int64}
/// The total size of the attribute data (in bytes).
/// Note: the value includes data of attributes that are not in use anymore.
/// Attributes that are contained in the write-ahead log only are not
/// reported in this figure.
///
/// @RESTSTRUCT{indexes,collection_figures,object,required,collection_figures_indexes}
/// @RESTSTRUCT{count,collection_figures_indexes,integer,required,int64}
/// The total number of indexes defined for the collection, including the pre-defined
/// indexes (e.g. primary index).
///
/// @RESTSTRUCT{size,collection_figures_indexes,integer,required,int64}
/// The total memory allocated for indexes in bytes.
///
/// @RESTSTRUCT{maxTick,collection_figures,integer,required,int64}
/// The tick of the last marker that was stored in a journal
/// of the collection. This might be 0 if the collection does not yet have
/// a journal.
///
/// @RESTSTRUCT{uncollectedLogfileEntries,collection_figures,integer,required,int64}
/// The number of markers in the write-ahead
/// log for this collection that have not been transferred to journals or datafiles.
///
/// @RESTSTRUCT{documentReferences,collection_figures,integer,optional,int64}
/// The number of references to documents in datafiles that JavaScript code
/// currently holds. This information can be used for debugging compaction and
/// unload issues.
///
/// @RESTSTRUCT{waitingFor,collection_figures,string,optional,string}
/// An optional string value that contains information about which object type is at the
/// head of the collection's cleanup queue. This information can be used for debugging
/// compaction and unload issues.
///
/// @RESTSTRUCT{compactionStatus,collection_figures,object,optional,compactionStatus_attributes}
/// @RESTSTRUCT{message,compactionStatus_attributes,string,optional,string}
/// The action that was performed when the compaction was last run for the collection.
/// This information can be used for debugging compaction issues.
///
/// @RESTSTRUCT{time,compactionStatus_attributes,string,optional,string}
/// The point in time the compaction for the collection was last executed.
/// This information can be used for debugging compaction issues.
///
/// @RESTREPLYBODY{journalSize,integer,required,int64}
/// The maximal size of a journal or datafile in bytes.
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// Using an identifier and requesting the figures of the collection:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionFigures}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn);
/// coll.save({"test":"hello"});
/// require("internal").wal.flush(true, true);
/// var url = "/_api/collection/"+ coll.name() + "/figures";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_get_api_collection_revision
/// @brief Retrieve the collections revision id
///
/// @RESTHEADER{GET /_api/collection/{collection-name}/revision, Return collection revision id}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// In addition to the above, the result will also contain the
/// collection's revision id. The revision id is a server-generated
/// string that clients can use to check whether data in a collection
/// has changed since the last revision check.
///
/// - *revision*: The collection revision id as a string.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// Retrieving the revision of a collection
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionRevision}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: false });
/// var url = "/_api/collection/"+ coll.name() + "/revision";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSA_get_api_collection_checksum
/// @brief returns a checksum for the specified collection
///
/// @RESTHEADER{GET /_api/collection/{collection-name}/checksum, Return checksum for the collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTQUERYPARAMETERS
///
/// @RESTQUERYPARAM{withRevisions,boolean,optional}
/// Whether or not to include document revision ids in the checksum calculation.
///
/// @RESTQUERYPARAM{withData,boolean,optional}
/// Whether or not to include document body data in the checksum calculation.
///
/// @RESTDESCRIPTION
/// Will calculate a checksum of the meta-data (keys and optionally revision ids) and
/// optionally the document data in the collection.
///
/// The checksum can be used to compare if two collections on different ArangoDB
/// instances contain the same contents. The current revision of the collection is
/// returned too so one can make sure the checksums are calculated for the same
/// state of data.
///
/// By default, the checksum will only be calculated on the *_key* system attribute
/// of the documents contained in the collection. For edge collections, the system
/// attributes *_from* and *_to* will also be included in the calculation.
///
/// By setting the optional query parameter *withRevisions* to *true*, then revision
/// ids (*_rev* system attributes) are included in the checksumming.
///
/// By providing the optional query parameter *withData* with a value of *true*,
/// the user-defined document attributes will be included in the calculation too.
/// **Note**: Including user-defined attributes will make the checksumming slower.
///
/// The response is a JSON object with the following attributes:
///
/// - *checksum*: The calculated checksum as a number.
///
/// - *revision*: The collection revision id as a string.
///
/// **Note**: this method is not available in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// Retrieving the checksum of a collection:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionChecksum}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn);
/// coll.save({ foo: "bar" });
/// var url = "/_api/collection/" + coll.name() + "/checksum";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// Retrieving the checksum of a collection including the collection data,
/// but not the revisions:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionGetCollectionChecksumNoRev}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn);
/// coll.save({ foo: "bar" });
/// var url = "/_api/collection/" + coll.name() + "/checksum?withRevisions=false&withData=true";
///
/// var response = logCurlRequest('GET', url);
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function get_api_collection (req, res) {
var name;
var result;
var sub;
// .............................................................................
// /_api/collection
// .............................................................................
if (req.suffix.length === 0 && req.parameters.id === undefined) {
get_api_collections(req, res);
return;
}
// .............................................................................
// /_api/collection/<name>
// .............................................................................
name = decodeURIComponent(req.suffix[0]);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
return;
}
var headers;
// .............................................................................
// /_api/collection/<name>
// .............................................................................
if (req.suffix.length === 1) {
result = collectionRepresentation(collection, false, false, false);
headers = {
location : databasePrefix(req, "/_api/collection/" + collection.name())
};
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
return;
}
if (req.suffix.length === 2) {
sub = decodeURIComponent(req.suffix[1]);
// .............................................................................
// /_api/collection/<identifier>/checksum
// .............................................................................
if (sub === "checksum") {
var withRevisions = false;
var withData = false;
var value;
if (req.parameters.hasOwnProperty('withRevisions')) {
value = req.parameters.withRevisions.toLowerCase();
if (value === 'true' || value === 'yes' || value === 'on' || value === 'y' || value === '1') {
withRevisions = true;
}
}
if (req.parameters.hasOwnProperty('withData')) {
value = req.parameters.withData.toLowerCase();
if (value === 'true' || value === 'yes' || value === 'on' || value === 'y' || value === '1') {
withData = true;
}
}
result = collectionRepresentation(collection, false, false, false);
var checksum = collection.checksum(withRevisions, withData);
result.checksum = checksum.checksum;
result.revision = checksum.revision;
actions.resultOk(req, res, actions.HTTP_OK, result);
}
// .............................................................................
// /_api/collection/<identifier>/figures
// .............................................................................
else if (sub === "figures") {
result = collectionRepresentation(collection, true, true, true);
headers = {
location : databasePrefix(req, "/_api/collection/" + collection.name() + "/figures")
};
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
// .............................................................................
// /_api/collection/<identifier>/count
// .............................................................................
else if (sub === "count") {
result = collectionRepresentation(collection, true, true, false);
headers = {
location : databasePrefix(req, "/_api/collection/" + collection.name() + "/count")
};
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
// .............................................................................
// /_api/collection/<identifier>/properties
// .............................................................................
else if (sub === "properties") {
result = collectionRepresentation(collection, true, false, false);
headers = {
location : databasePrefix(req, "/_api/collection/" + collection.name() + "/properties")
};
actions.resultOk(req, res, actions.HTTP_OK, result, headers);
}
// .............................................................................
// /_api/collection/<identifier>/revision
// .............................................................................
else if (sub === "revision") {
result = collectionRepresentation(collection, false, false, false);
result.revision = collection.revision();
actions.resultOk(req, res, actions.HTTP_OK, result);
}
else {
actions.resultNotFound(req, res, arangodb.ERROR_HTTP_NOT_FOUND,
"expecting one of the resources 'count',"
+" 'figures', 'properties', 'parameter'");
}
}
else {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expect GET /_api/collection/<collection-name>/<method>");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_put_api_collection_load
/// @brief loads a collection
///
/// @RESTHEADER{PUT /_api/collection/{collection-name}/load, Load collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// Loads a collection into memory. Returns the collection on success.
///
/// The request body object might optionally contain the following attribute:
///
/// - *count*: If set, this controls whether the return value should include
/// the number of documents in the collection. Setting *count* to
/// *false* may speed up loading a collection. The default value for
/// *count* is *true*.
///
/// On success an object with the following attributes is returned:
///
/// - *id*: The identifier of the collection.
///
/// - *name*: The name of the collection.
///
/// - *count*: The number of documents inside the collection. This is only
/// returned if the *count* input parameters is set to *true* or has
/// not been specified.
///
/// - *status*: The status of the collection as number.
///
/// - *type*: The collection type. Valid types are:
/// - 2: document collection
/// - 3: edges collection
///
/// - *isSystem*: If *true* then the collection is a system collection.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionIdentifierLoad}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/"+ coll.name() + "/load";
///
/// var response = logCurlRequest('PUT', url, '');
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function put_api_collection_load (req, res, collection) {
try {
collection.load();
var showCount = true;
var body = actions.getJsonBody(req, res);
if (body && body.hasOwnProperty("count")) {
showCount = body.count;
}
var result = collectionRepresentation(collection, false, showCount, false);
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_put_api_collection_unload
/// @brief unloads a collection
///
/// @RESTHEADER{PUT /_api/collection/{collection-name}/unload, Unload collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
///
/// @RESTDESCRIPTION
/// Removes a collection from memory. This call does not delete any documents.
/// You can use the collection afterwards; in which case it will be loaded into
/// memory, again. On success an object with the following attributes is
/// returned:
///
/// - *id*: The identifier of the collection.
///
/// - *name*: The name of the collection.
///
/// - *status*: The status of the collection as number.
///
/// - *type*: The collection type. Valid types are:
/// - 2: document collection
/// - 3: edges collection
///
/// - *isSystem*: If *true* then the collection is a system collection.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404* is returned.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionIdentifierUnload}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/"+ coll.name() + "/unload";
///
/// var response = logCurlRequest('PUT', url, '');
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function put_api_collection_unload (req, res, collection) {
try {
if (req.parameters.hasOwnProperty('flush')) {
var value = req.parameters.flush.toLowerCase();
if (value === 'true' || value === 'yes' || value === 'on' || value === 'y' || value === '1') {
if (collection.status() === 3 /* loaded */ &&
collection.figures().uncollectedLogfileEntries > 0) {
// flush WAL so uncollected logfile entries can get collected
require("internal").wal.flush();
}
}
}
// then unload
collection.unload();
var result = collectionRepresentation(collection);
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_put_api_collection_truncate
/// @brief truncates a collection
///
/// @RESTHEADER{PUT /_api/collection/{collection-name}/truncate, Truncate collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// Removes all documents from the collection, but leaves the indexes intact.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionIdentifierTruncate}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/"+ coll.name() + "/truncate";
///
/// var response = logCurlRequest('PUT', url, '');
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function put_api_collection_truncate (req, res, collection) {
try {
collection.truncate();
var result = collectionRepresentation(collection);
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_put_api_collection_properties
/// @brief changes a collection
///
/// @RESTHEADER{PUT /_api/collection/{collection-name}/properties, Change properties of a collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// Changes the properties of a collection. Expects an object with the
/// attribute(s)
///
/// - *waitForSync*: If *true* then creating or changing a
/// document will wait until the data has been synchronized to disk.
///
/// - *journalSize*: The maximal size of a journal or datafile in bytes.
/// The value must be at least `1048576` (1 MB). Note that when
/// changing the journalSize value, it will only have an effect for
/// additional journals or datafiles that are created. Already
/// existing journals or datafiles will not be affected.
///
/// On success an object with the following attributes is returned:
///
/// - *id*: The identifier of the collection.
///
/// - *name*: The name of the collection.
///
/// - *waitForSync*: The new value.
///
/// - *journalSize*: The new value.
///
/// - *status*: The status of the collection as number.
///
/// - *type*: The collection type. Valid types are:
/// - 2: document collection
/// - 3: edges collection
///
/// - *isSystem*: If *true* then the collection is a system collection.
///
/// - *isVolatile*: If *true* then the collection data will be
/// kept in memory only and ArangoDB will not write or sync the data
/// to disk.
///
/// - *doCompact*: Whether or not the collection will be compacted.
///
/// - *keyOptions*: JSON object which contains key generation options:
/// - *type*: specifies the type of the key generator. The currently
/// available generators are *traditional* and *autoincrement*.
/// - *allowUserKeys*: if set to *true*, then it is allowed to supply
/// own key values in the *_key* attribute of a document. If set to
/// *false*, then the key generator is solely responsible for
/// generating keys and supplying own key values in the *_key* attribute
/// of documents is considered an error.
///
/// **Note**: some other collection properties, such as *type*, *isVolatile*,
/// *numberOfShards* or *shardKeys* cannot be changed once a collection is
/// created.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
///
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionIdentifierPropertiesSync}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/"+ coll.name() + "/properties";
///
/// var response = logCurlRequest('PUT', url, {"waitForSync" : true });
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// db._drop(cn);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function put_api_collection_properties (req, res, collection) {
var body = actions.getJsonBody(req, res);
if (body === undefined) {
return;
}
try {
collection.properties(body);
var result = collectionRepresentation(collection, true);
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_put_api_collection_rename
/// @brief renames a collection
///
/// @RESTHEADER{PUT /_api/collection/{collection-name}/rename, Rename collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection to rename.
///
/// @RESTDESCRIPTION
/// Renames a collection. Expects an object with the attribute(s)
///
/// - *name*: The new name.
///
/// It returns an object with the attributes
///
/// - *id*: The identifier of the collection.
///
/// - *name*: The new name of the collection.
///
/// - *status*: The status of the collection as number.
///
/// - *type*: The collection type. Valid types are:
/// - 2: document collection
/// - 3: edges collection
///
/// - *isSystem*: If *true* then the collection is a system collection.
///
/// If renaming the collection succeeds, then the collection is also renamed in
/// all graph definitions inside the `_graphs` collection in the current database.
///
/// **Note**: this method is not available in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404*
/// is returned.
/// @EXAMPLES
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionIdentifierRename}
/// var cn = "products1";
/// var coll = db._create(cn);
/// var url = "/_api/collection/" + coll.name() + "/rename";
///
/// var response = logCurlRequest('PUT', url, { name: "newname" });
///
/// assert(response.code === 200);
/// db._flushCache();
/// db._drop("newname");
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function put_api_collection_rename (req, res, collection) {
var body = actions.getJsonBody(req, res);
if (body === undefined) {
return;
}
if (! body.hasOwnProperty("name")) {
actions.resultBad(req, res, arangodb.ERROR_ARANGO_ILLEGAL_NAME,
"name must be non-empty");
return;
}
var name = body.name;
try {
collection.rename(name);
var result = collectionRepresentation(collection);
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_put_api_collection_rotate
/// @brief rotates the journal of a collection
///
/// @RESTHEADER{PUT /_api/collection/{collection-name}/rotate, Rotate journal of a collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection.
///
/// @RESTDESCRIPTION
/// Rotates the journal of a collection. The current journal of the collection will be closed
/// and made a read-only datafile. The purpose of the rotate method is to make the data in
/// the file available for compaction (compaction is only performed for read-only datafiles, and
/// not for journals).
///
/// Saving new data in the collection subsequently will create a new journal file
/// automatically if there is no current journal.
///
/// It returns an object with the attributes
///
/// - *result*: will be *true* if rotation succeeded
///
/// **Note**: This method is not available in a cluster.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the collection currently has no journal, *HTTP 400* is returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404* is returned.
///
/// @EXAMPLES
///
/// Rotating the journal:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionRotate}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn);
/// coll.save({ "test" : true });
/// require("internal").wal.flush(true, true);
///
/// var url = "/_api/collection/"+ coll.name() + "/rotate";
/// var response = logCurlRequest('PUT', url, { });
///
/// assert(response.code === 200);
/// db._flushCache();
/// db._drop(cn);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// Rotating if no journal exists:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionRotateNoJournal}
/// var cn = "products";
/// db._drop(cn);
/// var coll = db._create(cn);
/// var url = "/_api/collection/"+ coll.name() + "/rotate";
///
/// var response = logCurlRequest('PUT', url, { });
///
/// assert(response.code === 400);
/// db._flushCache();
/// db._drop(cn);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function put_api_collection_rotate (req, res, collection) {
try {
collection.rotate();
actions.resultOk(req, res, actions.HTTP_OK, { result: true });
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief changes a collection
////////////////////////////////////////////////////////////////////////////////
function put_api_collection (req, res) {
if (req.suffix.length !== 2) {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expected PUT /_api/collection/<collection-name>/<action>");
return;
}
var name = decodeURIComponent(req.suffix[0]);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
return;
}
var sub = decodeURIComponent(req.suffix[1]);
if (sub === "load") {
put_api_collection_load(req, res, collection);
}
else if (sub === "unload") {
put_api_collection_unload(req, res, collection);
collection = null;
// run garbage collection once in all threads
require("internal").executeGlobalContextFunction("collectGarbage");
}
else if (sub === "truncate") {
put_api_collection_truncate(req, res, collection);
}
else if (sub === "properties") {
put_api_collection_properties(req, res, collection);
}
else if (sub === "rename") {
put_api_collection_rename(req, res, collection);
}
else if (sub === "rotate") {
put_api_collection_rotate(req, res, collection);
}
else {
actions.resultNotFound(req, res, arangodb.ERROR_HTTP_NOT_FOUND,
"expecting one of the actions 'load', 'unload',"
+ " 'truncate', 'properties', 'rename'");
}
}
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_delete_api_collection
/// @brief drops a collection
///
/// @RESTHEADER{DELETE /_api/collection/{collection-name}, Drops collection}
///
/// @RESTURLPARAMETERS
///
/// @RESTURLPARAM{collection-name,string,required}
/// The name of the collection to drop.
///
/// @RESTDESCRIPTION
/// Drops the collection identified by *collection-name*.
///
/// If the collection was successfully dropped, an object is returned with
/// the following attributes:
///
/// - *error*: *false*
///
/// - *id*: The identifier of the dropped collection.
///
/// @RESTRETURNCODES
///
/// @RESTRETURNCODE{400}
/// If the *collection-name* is missing, then a *HTTP 400* is
/// returned.
///
/// @RESTRETURNCODE{404}
/// If the *collection-name* is unknown, then a *HTTP 404* is returned.
///
/// @EXAMPLES
///
/// Using an identifier:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionDeleteCollectionIdentifier}
/// var cn = "products1";
/// var coll = db._create(cn, { waitForSync: true });
/// var url = "/_api/collection/"+ coll._id;
///
/// var response = logCurlRequest('DELETE', url);
/// db[cn] = undefined;
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
///
/// Using a name:
///
/// @EXAMPLE_ARANGOSH_RUN{RestCollectionDeleteCollectionName}
/// var cn = "products1";
/// db._drop(cn);
/// db._create(cn);
/// var url = "/_api/collection/products1";
///
/// var response = logCurlRequest('DELETE', url);
/// db[cn] = undefined;
///
/// assert(response.code === 200);
///
/// logJsonResponse(response);
/// @END_EXAMPLE_ARANGOSH_RUN
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
function delete_api_collection (req, res) {
if (req.suffix.length !== 1) {
actions.resultBad(req, res, arangodb.ERROR_HTTP_BAD_PARAMETER,
"expected DELETE /_api/collection/<collection-name>");
}
else {
var name = decodeURIComponent(req.suffix[0]);
var collection = arangodb.db._collection(name);
if (collection === null) {
actions.collectionNotFound(req, res, name);
}
else {
try {
var result = {
id : collection._id
};
collection.drop();
actions.resultOk(req, res, actions.HTTP_OK, result);
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
/// @brief handles a collection request
////////////////////////////////////////////////////////////////////////////////
actions.defineHttp({
url : "_api/collection",
callback : function (req, res) {
try {
if (req.requestType === actions.GET) {
get_api_collection(req, res);
}
else if (req.requestType === actions.DELETE) {
delete_api_collection(req, res);
}
else if (req.requestType === actions.POST) {
post_api_collection(req, res);
}
else if (req.requestType === actions.PUT) {
put_api_collection(req, res);
}
else {
actions.resultUnsupported(req, res);
}
}
catch (err) {
actions.resultException(req, res, err, undefined, false);
}
}
});
// -----------------------------------------------------------------------------
// --SECTION-- END-OF-FILE
// -----------------------------------------------------------------------------
// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|/// @startDocuBlock\\|// --SECTION--\\|/// @\\}"
// End: