1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Jan Steemann 2014-09-16 22:09:09 +02:00
commit 988a622b54
8 changed files with 255 additions and 70 deletions

View File

@ -85,6 +85,29 @@ do the same for all routes of a controller. For this purpose
use the *allRoutes* object of the according controller. use the *allRoutes* object of the according controller.
The following methods are available. The following methods are available.
*Examples*
Provide an error response for all routes handled by this controller:
```js
ctrl.allRoutes
.errorResponse(Unauthorized, 401, 'Not authenticated.')
.errorResponse(NotFound, 404, 'Document not found.')
.errorResponse(ImATeapot, 418, 'I\'m a teapot.');
ctrl.get('/some/route', function (req, res) {
// ...
throw new NotFound('The document does not exist');
// ...
}); // no errorResponse needed here
ctrl.get('/another/route', function (req, res) {
// ...
throw new NotFound('I made you a cookie but I ated it');
// ...
}); // no errorResponse needed here either
```
!SUBSECTION Buffer Error Response !SUBSECTION Buffer Error Response
<!-- js/server/modules/org/arangodb/foxx/request_context.js --> <!-- js/server/modules/org/arangodb/foxx/request_context.js -->
@startDocuBlock JSF_foxx_RequestContextBuffer_errorResponse @startDocuBlock JSF_foxx_RequestContextBuffer_errorResponse

View File

@ -191,7 +191,6 @@ function FILTER (list, examples) {
for (i = 0; i < list.length; ++i) { for (i = 0; i < list.length; ++i) {
var element = list[i]; var element = list[i];
if (MATCHES(element, examples, false)) { if (MATCHES(element, examples, false)) {
result.push(element); result.push(element);
} }
@ -3860,7 +3859,6 @@ function MATCHES (element, examples, returnIndex) {
if (! Array.isArray(examples)) { if (! Array.isArray(examples)) {
examples = [ examples ]; examples = [ examples ];
} }
if (examples.length === 0) { if (examples.length === 0) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "MATCHES"); THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "MATCHES");
} }
@ -3870,7 +3868,6 @@ function MATCHES (element, examples, returnIndex) {
for (i = 0; i < examples.length; ++i) { for (i = 0; i < examples.length; ++i) {
var example = examples[i]; var example = examples[i];
var result = true; var result = true;
if (TYPEWEIGHT(example) !== TYPEWEIGHT_DOCUMENT) { if (TYPEWEIGHT(example) !== TYPEWEIGHT_DOCUMENT) {
THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "MATCHES"); THROW(INTERNAL.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, "MATCHES");
} }
@ -5997,6 +5994,11 @@ function GENERAL_GRAPH_NEIGHBORS (graphName,
options.startVertexCollectionRestriction = options.vertexCollectionRestriction; options.startVertexCollectionRestriction = options.vertexCollectionRestriction;
} }
} }
if (options.neighborExamples) {
if (typeof options.neighborExamples === "string") {
options.neighborExamples = {_id : options.neighborExamples};
}
}
var neighbors = [], var neighbors = [],
params = TRAVERSAL_PARAMS(), params = TRAVERSAL_PARAMS(),
factory = TRAVERSAL.generalGraphDatasourceFactory(graphName); factory = TRAVERSAL.generalGraphDatasourceFactory(graphName);
@ -6005,14 +6007,12 @@ function GENERAL_GRAPH_NEIGHBORS (graphName,
params.paths = true; params.paths = true;
params.visitor = TRAVERSAL_NEIGHBOR_VISITOR; params.visitor = TRAVERSAL_NEIGHBOR_VISITOR;
var fromVertices = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options); var fromVertices = RESOLVE_GRAPH_TO_FROM_VERTICES(graphName, options);
if (options.edgeExamples) { if (options.edgeExamples) {
params.followEdges = options.edgeExamples; params.followEdges = options.edgeExamples;
} }
if (options.edgeCollectionRestriction) { if (options.edgeCollectionRestriction) {
params.edgeCollectionRestriction = options.edgeCollectionRestriction; params.edgeCollectionRestriction = options.edgeCollectionRestriction;
} }
fromVertices.forEach(function (v) { fromVertices.forEach(function (v) {
var e = TRAVERSAL_FUNC("GRAPH_NEIGHBORS", var e = TRAVERSAL_FUNC("GRAPH_NEIGHBORS",
factory, factory,

View File

@ -346,7 +346,11 @@ extend(Controller.prototype, {
/// The before function takes a *path* on which it should watch and a /// The before function takes a *path* on which it should watch and a
/// function that it should execute before the routing takes place. If you do /// function that it should execute before the routing takes place. If you do
/// omit the path, the function will be executed before each request, no matter /// omit the path, the function will be executed before each request, no matter
/// the path. Your function gets a Request and a Response object. /// the path. Your function gets a Request and a Response object.
///
/// If your callback returns the Boolean value *false*, the route handling
/// will not proceed. You can use this to intercept invalid or unauthorized
/// requests and prevent them from being passed to the matching routes.
/// ///
/// @EXAMPLES /// @EXAMPLES
/// ///
@ -371,8 +375,10 @@ extend(Controller.prototype, {
url: {match: path}, url: {match: path},
action: { action: {
callback: function (req, res, opts, next) { callback: function (req, res, opts, next) {
func(req, res, opts); var result = func(req, res, opts);
next(); if (result !== false) {
next();
}
} }
} }
}); });

View File

@ -192,13 +192,14 @@ function extendContext (context, app, root) {
"use strict"; "use strict";
var cp = context.collectionPrefix; var cp = context.collectionPrefix;
var cname = "";
if (cp !== "" && cp !== "_") { if (cp !== "") {
cp += "_"; cname = cp + "_";
} }
context.collectionName = function (name) { context.collectionName = function (name) {
var replaced = ((cp + name).replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '')).substr(0, 64); var replaced = (cname + name).replace(/[^a-zA-Z0-9]/g, '_').replace(/(^_+|_+$)/g, '').substr(0, 64);
if (replaced.length === 0) { if (replaced.length === 0) {
throw new Error("Cannot derive collection name from '" + name + "'"); throw new Error("Cannot derive collection name from '" + name + "'");

View File

@ -28,6 +28,7 @@
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
var Repository, var Repository,
Model = require("org/arangodb/foxx/model").Model,
_ = require("underscore"), _ = require("underscore"),
extend = require('org/arangodb/extend').extend; extend = require('org/arangodb/extend').extend;
@ -82,7 +83,7 @@ Repository = function (collection, opts) {
/// @endDocuBlock /// @endDocuBlock
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
this.modelPrototype = this.options.model || require("org/arangodb/foxx/model").Model; this.modelPrototype = this.options.model || Model;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_foxx_repository_prefix /// @startDocuBlock JSF_foxx_repository_prefix
@ -262,7 +263,7 @@ _.extend(Repository.prototype, {
remove: function (model) { remove: function (model) {
'use strict'; 'use strict';
var id = model.get('_id'); var id = model.get('_id');
this.collection.remove(id); return this.collection.remove(id);
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -281,7 +282,7 @@ _.extend(Repository.prototype, {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
removeById: function (id) { removeById: function (id) {
'use strict'; 'use strict';
this.collection.remove(id); return this.collection.remove(id);
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -299,7 +300,7 @@ _.extend(Repository.prototype, {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
removeByExample: function (example) { removeByExample: function (example) {
'use strict'; 'use strict';
this.collection.removeByExample(example); return this.collection.removeByExample(example);
}, },
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
@ -311,7 +312,7 @@ _.extend(Repository.prototype, {
/// `FoxxRepository#replace(model)` /// `FoxxRepository#replace(model)`
/// ///
/// Find the model in the database by its *_id* and replace it with this version. /// Find the model in the database by its *_id* and replace it with this version.
/// Expects a model. Sets the Revision of the model. /// Expects a model. Sets the revision of the model.
/// Returns the model. /// Returns the model.
/// ///
/// @EXAMPLES /// @EXAMPLES
@ -324,7 +325,7 @@ _.extend(Repository.prototype, {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
replace: function (model) { replace: function (model) {
'use strict'; 'use strict';
var id = model.get("_id"), var id = model.get("_id") || model.get("_key"),
data = model.forDB(), data = model.forDB(),
id_and_rev = this.collection.replace(id, data); id_and_rev = this.collection.replace(id, data);
model.set(id_and_rev); model.set(id_and_rev);
@ -333,11 +334,12 @@ _.extend(Repository.prototype, {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_foxx_repository_replaceById /// @startDocuBlock JSF_foxx_repository_replaceById
/// `FoxxRepository#replaceById(id, model)` /// `FoxxRepository#replaceById(id, object)`
/// ///
/// Find the model in the database by the given ID and replace it with the given. /// Find the item in the database by the given ID and replace it with the
/// model. /// given object's attributes.
/// Sets the ID and Revision of the model and also returns it. ///
/// If the object is a model, updates the model's revision and returns the model.
/// ///
/// @EXAMPLES /// @EXAMPLES
/// ///
@ -346,21 +348,22 @@ _.extend(Repository.prototype, {
/// ``` /// ```
/// @endDocuBlock /// @endDocuBlock
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
replaceById: function (id, model) { replaceById: function (id, data) {
'use strict'; 'use strict';
var data = model.forDB(), if (data instanceof Model) {
id_and_rev = this.collection.replace(id, data); var id_and_rev = this.collection.replace(id, data.forDB());
model.set(id_and_rev); data.set(id_and_rev);
return model; return data;
}
return this.collection.replace(id, data);
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_foxx_repository_replaceByExample /// @startDocuBlock JSF_foxx_repository_replaceByExample
/// `FoxxRepository#replaceByExample(example, model)` /// `FoxxRepository#replaceByExample(example, object)`
/// ///
/// Find the model in the database by the given example and replace it with the given. /// Find every matching item by example and replace it with the attributes in
/// model. /// the provided object.
/// Sets the ID and Revision of the model and also returns it.
/// ///
/// @EXAMPLES /// @EXAMPLES
/// ///
@ -369,24 +372,46 @@ _.extend(Repository.prototype, {
/// ``` /// ```
/// @endDocuBlock /// @endDocuBlock
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
replaceByExample: function (example, model) { replaceByExample: function (example, data) {
'use strict'; 'use strict';
var data = model.forDB(), return this.collection.replaceByExample(example, data);
idAndRev = this.collection.replaceByExample(example, data);
model.set(idAndRev);
return model;
}, },
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// --SUBSECTION-- Updating Entries // --SUBSECTION-- Updating Entries
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_foxx_repository_update
/// `FoxxRepository#update(model, object)`
///
/// Find the model in the database by its *_id* and update it with the given object.
/// Expects a model. Sets the revision of the model and updates its properties.
/// Returns the model.
///
/// @EXAMPLES
///
/// ```javascript
/// repository.update(myModel, {name: 'Jan Steeman'});
/// ```
/// @endDocuBlock
////////////////////////////////////////////////////////////////////////////////
update: function (model, data) {
'use strict';
var id = model.get("_id") || model.get("_key"),
id_and_rev = this.collection.update(id, data);
model.set(data);
model.set(id_and_rev);
return model;
},
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_foxx_repository_updateById /// @startDocuBlock JSF_foxx_repository_updateById
/// `FoxxRepository#updateById(id, object)` /// `FoxxRepository#updateById(id, object)`
/// ///
/// Find an item by ID and update it with the attributes in the provided object. /// Find an item by ID and update it with the attributes in the provided object.
/// Returns the updated model. ///
/// If the object is a model, updates the model's revision and returns the model.
/// ///
/// @EXAMPLES /// @EXAMPLES
/// ///
@ -395,17 +420,22 @@ _.extend(Repository.prototype, {
/// ``` /// ```
/// @endDocuBlock /// @endDocuBlock
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
updateById: function (id, updates) { updateById: function (id, data) {
'use strict'; 'use strict';
this.collection.update(id, updates); if (data instanceof Model) {
var id_and_rev = this.collection.update(id, data.forDB());
data.set(id_and_rev);
return data;
}
return this.collection.update(id, data);
}, },
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
/// @startDocuBlock JSF_foxx_repository_updateByExample /// @startDocuBlock JSF_foxx_repository_updateByExample
/// `FoxxRepository#updateByExample(example, object)` /// `FoxxRepository#updateByExample(example, object)`
/// ///
/// Find an item by example and update it with the attributes in the provided object. /// Find every matching item by example and update it with the attributes in
/// Returns the updated model. /// the provided object.
/// ///
/// @EXAMPLES /// @EXAMPLES
/// ///
@ -414,9 +444,9 @@ _.extend(Repository.prototype, {
/// ``` /// ```
/// @endDocuBlock /// @endDocuBlock
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
updateByExample: function (example, updates) { updateByExample: function (example, data) {
'use strict'; 'use strict';
this.collection.updateByExample(example, updates); return this.collection.updateByExample(example, data);
}, },
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@ -220,13 +220,23 @@ extend(RequestContext.prototype, {
/// ///
/// You can also provide a description of this parameter. /// You can also provide a description of this parameter.
/// ///
/// @EXAMPLES /// *Examples*
///
/// ```js
/// app.get("/foxx/:id", function {
/// // Do something
/// }).pathParam("id", type: joi.number().integer().required().description("Id of the Foxx"));
/// ```
///
/// You can also pass in a configuration object instead:
/// ///
/// ```js /// ```js
/// app.get("/foxx/:id", function { /// app.get("/foxx/:id", function {
/// // Do something /// // Do something
/// }).pathParam("id", { /// }).pathParam("id", {
/// type: joi.number().integer().required().description("Id of the Foxx") /// type: joi.number().integer(),
/// required: true,
/// description: "Id of the Foxx"
/// }); /// });
/// ``` /// ```
/// @endDocuBlock /// @endDocuBlock
@ -239,9 +249,16 @@ extend(RequestContext.prototype, {
type = attributes.type, type = attributes.type,
required = attributes.required, required = attributes.required,
description = attributes.description, description = attributes.description,
constraint = type, constraint, regexType, cfg;
regexType = type,
cfg; if (attributes.isJoi) {
type = attributes;
required = undefined;
description = undefined;
}
constraint = type;
regexType = type;
// deprecated: assume type.describe is always a function // deprecated: assume type.describe is always a function
if (type && typeof type.describe === 'function') { if (type && typeof type.describe === 'function') {
@ -306,6 +323,19 @@ extend(RequestContext.prototype, {
/// ```js /// ```js
/// app.get("/foxx", function { /// app.get("/foxx", function {
/// // Do something /// // Do something
/// }).queryParam("id",
/// joi.number().integer()
/// .required()
/// .description("Id of the Foxx")
/// .meta({allowMultiple: false})
/// });
/// ```
///
/// You can also pass in a configuration object instead:
///
/// ```js
/// app.get("/foxx", function {
/// // Do something
/// }).queryParam("id", { /// }).queryParam("id", {
/// type: joi.number().integer().required().description("Id of the Foxx"), /// type: joi.number().integer().required().description("Id of the Foxx"),
/// allowMultiple: false /// allowMultiple: false
@ -319,8 +349,17 @@ extend(RequestContext.prototype, {
var type = attributes.type, var type = attributes.type,
required = attributes.required, required = attributes.required,
description = attributes.description, description = attributes.description,
constraint = type, allowMultiple = attributes.allowMultiple,
cfg; constraint, cfg;
if (attributes.isJoi) {
type = attributes;
required = undefined;
description = undefined;
allowMultiple = undefined;
}
constraint = type;
// deprecated: assume type.describe is always a function // deprecated: assume type.describe is always a function
if (type && typeof type.describe === 'function') { if (type && typeof type.describe === 'function') {
@ -330,6 +369,9 @@ extend(RequestContext.prototype, {
if (typeof description === 'string') { if (typeof description === 'string') {
constraint = constraint.description(description); constraint = constraint.description(description);
} }
if (typeof allowMultiple === 'boolean') {
constraint = constraint.meta({allowMultiple: allowMultiple});
}
this.constraints.queryParams[paramName] = constraint; this.constraints.queryParams[paramName] = constraint;
cfg = constraint.describe(); cfg = constraint.describe();
if (Array.isArray(cfg)) { if (Array.isArray(cfg)) {
@ -338,8 +380,18 @@ extend(RequestContext.prototype, {
} else { } else {
type = cfg.type; type = cfg.type;
} }
required = Boolean(cfg.flags && cfg.flags.presense === 'required'); required = Boolean(cfg.flags && cfg.flags.presence === 'required');
description = cfg.description; description = cfg.description;
if (cfg.meta) {
if (!Array.isArray(cfg.meta)) {
cfg.meta = [cfg.meta];
}
_.each(cfg.meta, function (meta) {
if (meta && typeof meta.allowMultiple === 'boolean') {
allowMultiple = meta.allowMultiple;
}
});
}
if ( if (
type === 'number' && type === 'number' &&
_.isArray(cfg.rules) && _.isArray(cfg.rules) &&
@ -356,7 +408,7 @@ extend(RequestContext.prototype, {
description, description,
type, type,
required, required,
attributes.allowMultiple Boolean(allowMultiple)
); );
return this; return this;
}, },

View File

@ -288,25 +288,39 @@ describe('Repository Methods', function () {
}); });
it('should replace by example', function () { it('should replace by example', function () {
var model = new Model({}), var example = createSpy('example'),
idAndRev = createSpy('idAndRev'), data = createSpy('data');
example = createSpy('example'),
data = createSpy('data'),
result;
spyOn(model, 'forDB').and.returnValue(data); instance.replaceByExample(example, data);
spyOn(model, 'set');
collection.replaceByExample.and.returnValue(idAndRev);
result = instance.replaceByExample(example, model);
expect(result).toBe(model);
expect(model.set.calls.argsFor(0)).toEqual([idAndRev]);
expect(collection.replaceByExample.calls.argsFor(0)).toEqual([example, data]); expect(collection.replaceByExample.calls.argsFor(0)).toEqual([example, data]);
}); });
}); });
describe('for updating entries', function () { describe('for updating entries', function () {
it('should allow to update by model', function () {
var model = new Model({}),
idAndRev = createSpy('idAndRev'),
id = createSpy('id'),
data = createSpy('data'),
updates = createSpy('updates'),
result;
spyOn(model, 'get').and.returnValue(id);
spyOn(model, 'forDB').and.returnValue(data);
spyOn(model, 'set');
collection.update.and.returnValue(idAndRev);
result = instance.update(model, updates);
expect(result).toBe(model);
expect(model.set.calls.allArgs().length).toEqual(2);
expect(model.set.calls.allArgs()).toContain([idAndRev]);
expect(model.set.calls.allArgs()).toContain([updates]);
expect(collection.update.calls.argsFor(0)).toEqual([id, updates]);
expect(model.get.calls.argsFor(0)).toEqual(['_id']);
});
it('should update by id', function () { it('should update by id', function () {
var id = createSpy('id'), var id = createSpy('id'),
updates = createSpy('updates'), updates = createSpy('updates'),
@ -320,13 +334,11 @@ describe('Repository Methods', function () {
it('should update by example', function () { it('should update by example', function () {
var example = createSpy('example'), var example = createSpy('example'),
updates = createSpy('updates'), data = createSpy('data');
idAndRev = createSpy('idAndRev');
collection.updateByExample.and.returnValue(idAndRev); instance.updateByExample(example, data);
instance.updateByExample(example, updates);
expect(collection.updateByExample.calls.argsFor(0)).toEqual([example, updates]); expect(collection.updateByExample.calls.argsFor(0)).toEqual([example, data]);
}); });
}); });

View File

@ -514,6 +514,21 @@ function DocumentationAndConstraintsSpec () {
assertEqual(context.constraints.urlParams, {id: constraint}); assertEqual(context.constraints.urlParams, {id: constraint});
}, },
testDefinePathParamShorthand: function () {
var constraint = joi.number().integer().description("Id of the Foxx"),
context = app.get('/foxx/:id', function () {
//nothing
}).pathParam("id", constraint);
assertEqual(routes.length, 1);
assertEqual(routes[0].url.constraint.id, "/[0-9]+/");
assertEqual(routes[0].docs.parameters[0].paramType, "path");
assertEqual(routes[0].docs.parameters[0].name, "id");
assertEqual(routes[0].docs.parameters[0].description, "Id of the Foxx");
assertEqual(routes[0].docs.parameters[0].dataType, "integer");
assertEqual(context.constraints.urlParams, {id: constraint});
},
testDefinePathCaseParam: function () { testDefinePathCaseParam: function () {
var constraint = joi.number().integer().description("Id of the Foxx"), var constraint = joi.number().integer().description("Id of the Foxx"),
context = app.get('/foxx/:idParam', function () { context = app.get('/foxx/:idParam', function () {
@ -592,10 +607,56 @@ function DocumentationAndConstraintsSpec () {
context = app.get('/foxx', function () { context = app.get('/foxx', function () {
//nothing //nothing
}).queryParam("a", { }).queryParam("a", {
type: constraint, type: constraint
allowMultiple: true
}); });
assertEqual(routes.length, 1);
assertEqual(routes[0].docs.parameters[0].paramType, "query");
assertEqual(routes[0].docs.parameters[0].name, "a");
assertEqual(routes[0].docs.parameters[0].description, "The value of an a");
assertEqual(routes[0].docs.parameters[0].dataType, "integer");
assertEqual(routes[0].docs.parameters[0].required, false);
assertEqual(routes[0].docs.parameters[0].allowMultiple, false);
assertEqual(context.constraints.queryParams, {a: constraint});
},
testDefineQueryParamWithOverrides: function () {
var constraint = joi.number().integer(),
context = app.get('/foxx', function () {
//nothing
}).queryParam("a", {
type: constraint,
description: "The value of an a",
allowMultiple: true,
required: true
});
assertEqual(routes.length, 1);
assertEqual(routes[0].docs.parameters[0].paramType, "query");
assertEqual(routes[0].docs.parameters[0].name, "a");
assertEqual(routes[0].docs.parameters[0].description, "The value of an a");
assertEqual(routes[0].docs.parameters[0].dataType, "integer");
print(0)
assertEqual(routes[0].docs.parameters[0].required, true);
print(1)
assertEqual(routes[0].docs.parameters[0].allowMultiple, true);
print(2)
assertEqual(context.constraints.queryParams, {
a: constraint
.description("The value of an a")
.meta({allowMultiple: true})
.required()
});
},
testDefineQueryParamShorthand: function () {
var constraint = joi.number().integer()
.description("The value of an a")
.meta({allowMultiple: true}),
context = app.get('/foxx', function () {
//nothing
}).queryParam("a", constraint);
assertEqual(routes.length, 1); assertEqual(routes.length, 1);
assertEqual(routes[0].docs.parameters[0].paramType, "query"); assertEqual(routes[0].docs.parameters[0].paramType, "query");
assertEqual(routes[0].docs.parameters[0].name, "a"); assertEqual(routes[0].docs.parameters[0].name, "a");