Skip to content

Commit

Permalink
adding hasQuery() for query string value checking - closes #71
Browse files Browse the repository at this point in the history
  • Loading branch information
rodneyrehm committed Mar 16, 2013
1 parent ff4aa7f commit cc18c99
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 20 deletions.
149 changes: 130 additions & 19 deletions src/URI.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,12 @@ function escapeRegEx(string) {
return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
}

function getType(value) {
return String(Object.prototype.toString.call(value)).slice(8, -1);
}

function isArray(obj) {
return String(Object.prototype.toString.call(obj)) === "[object Array]";
return getType(obj) === "Array";
}

function filterArrayValues(data, value) {
Expand All @@ -85,6 +89,57 @@ function filterArrayValues(data, value) {
return data;
}

function arrayContains(list, value) {
var i, length;

// value may be string, number, array, regexp
if (isArray(value)) {
// Note: this can be optimized to O(n) (instead of current O(m * n))
for (i = 0, length = value.length; i < length; i++) {
if (!arrayContains(list, value[i])) {
return false;
}
}

return true;
}

var _type = getType(value);
for (i = 0, length = list.length; i < length; i++) {
if (_type === 'RegExp') {
if (typeof list[i] === 'string' && list[i].match(value)) {
return true;
}
} else if (list[i] === value) {
return true;
}
}

return false;
}

function arraysEqual(one, two) {
if (!isArray(one) || !isArray(two)) {
return false;
}

// arrays can't be equal if they have different amount of content
if (one.length !== two.length) {
return false;
}

one.sort();
two.sort();

for (var i = 0, l = one.length; i < l; i++) {
if (one[i] !== two[i]) {
return false;
}
}

return true;
}

URI._parts = function() {
return {
protocol: null,
Expand Down Expand Up @@ -551,6 +606,73 @@ URI.removeQuery = function(data, name, value) {
throw new TypeError("URI.addQuery() accepts an object, string as the first parameter");
}
};
URI.hasQuery = function(data, name, value, withinArray) {
if (typeof name === "object") {
for (var key in name) {
if (hasOwn.call(name, key)) {
if (!URI.hasQuery(data, key, name[key])) {
return false;
}
}
}

return true;
} else if (typeof name !== "string") {
throw new TypeError("URI.hasQuery() accepts an object, string as the name parameter");
}

switch (getType(value)) {
case 'Undefined':
// true if exists (but may be empty)
return name in data; // data[name] !== undefined;

case 'Boolean':
// true if exists and non-empty
var _booly = Boolean(isArray(data[name]) ? data[name].length : data[name]);
return value === _booly;

case 'Function':
// allow complex comparison
return !!value(data[name], name, data);

case 'Array':
if (!isArray(data[name])) {
return false;
}

var op = withinArray ? arrayContains : arraysEqual;
return op(data[name], value);

case 'RegExp':
if (!isArray(data[name])) {
return Boolean(data[name] && data[name].match(value));
}

if (!withinArray) {
return false;
}

return arrayContains(data[name], value);

case 'Number':
value = String(value);
// omit break;
case 'String':
if (!isArray(data[name])) {
return data[name] === value;
}

if (!withinArray) {
return false;
}

return arrayContains(data[name], value);

default:
throw new TypeError("URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter");
}
};


URI.commonPath = function(one, two) {
var length = Math.min(one.length, two.length);
Expand Down Expand Up @@ -1293,9 +1415,14 @@ p.removeQuery = function(name, value, build) {
this.build(!build);
return this;
};
p.hasQuery = function(name, value, withinArray) {
var data = URI.parseQuery(this._parts.query);
return URI.hasQuery(data, name, value, withinArray);
};
p.setSearch = p.setQuery;
p.addSearch = p.addQuery;
p.removeSearch = p.removeQuery;
p.hasSearch = p.hasQuery;

// sanitizing URLs
p.normalize = function() {
Expand Down Expand Up @@ -1643,24 +1770,8 @@ p.equals = function(uri) {
if (one_map[key] !== two_map[key]) {
return false;
}
} else {
if (!isArray(two_map[key])) {
return false;
}

// arrays can't be equal if they have different amount of content
if (one_map[key].length !== two_map[key].length) {
return false;
}

one_map[key].sort();
two_map[key].sort();

for (var i = 0, l = one_map[key].length; i < l; i++) {
if (one_map[key][i] !== two_map[key][i]) {
return false;
}
}
} else if (!arraysEqual(one_map[key], two_map[key])) {
return false;
}

checked[key] = true;
Expand Down
61 changes: 60 additions & 1 deletion test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ test("query callback", function() {
u.query(function(data) {
return {
bla: 'blubb'
}
};
});
equal(u.query(), 'bla=blubb', "overwrite returned value");
});
Expand Down Expand Up @@ -689,6 +689,65 @@ test("duplicateQueryParameters", function() {
u.addQuery('bar', 1);
equal(u.toString(), '?bar=1&bar=1&bar=1&bar=1', "parameters NOT de-duplicated after addQuery()");
});
test("hasQuery", function() {
var u = URI('?string=bar&list=one&list=two&number=123&null&empty=');

// exists
equal(u.hasQuery('string'), true, "simple exists check - passing");
equal(u.hasQuery('nono'), false, "simple exists check - failing");

// truthy value
equal(u.hasQuery('string', true), true, "has truthy value check - passing string");
equal(u.hasQuery('number', true), true, "has truthy value check - passing number");
equal(u.hasQuery('list', true), true, "has truthy value check - passing list");
equal(u.hasQuery('empty', true), false, "has truthy value check - failing empty");
equal(u.hasQuery('null', true), false, "has truthy value check - failing null");

// falsy value
equal(u.hasQuery('string', false), false, "has falsy value check - failing string");
equal(u.hasQuery('number', false), false, "has falsy value check - failing number");
equal(u.hasQuery('list', false), false, "has falsy value check - failing list");
equal(u.hasQuery('empty', false), true, "has falsy value check - passing empty");
equal(u.hasQuery('null', false), true, "has falsy value check - passing null");

// match value
equal(u.hasQuery('string', "bar"), true, "value check - passing string");
equal(u.hasQuery('number', 123), true, "value check - passing number");
equal(u.hasQuery('number', "123"), true, "value check - passing number as string");
equal(u.hasQuery('list', "one"), false, "value check - failing list");
equal(u.hasQuery('empty', ""), true, "value check - passing empty");
equal(u.hasQuery('null', ""), false, "value check - failing null");

// matching RegExp
equal(u.hasQuery('string', /ar$/), true, "RegExp check - passing string");
equal(u.hasQuery('number', /2/), true, "RegExp check - passing number");
equal(u.hasQuery('string', /nono/), false, "RegExp check - failing string");
equal(u.hasQuery('number', /999/), false, "RegExp check - failing number");

// matching array
equal(u.hasQuery('string', ['one']), false, "array check - failing string");
equal(u.hasQuery('list', ['one']), false, "array check - failing incomplete list");
equal(u.hasQuery('list', ['one', 'two']), true, "array check - passing list");
equal(u.hasQuery('list', ['two', 'one']), true, "array check - passing unsorted list");

// matching part of array
equal(u.hasQuery('string', ['one'], true), false, "in array check - failing string");
equal(u.hasQuery('list', ['one'], true), true, "in array check - passing incomplete list");
equal(u.hasQuery('list', ['one', 'two'], true), true, "in array check - passing list");
equal(u.hasQuery('list', ['two', 'one'], true), true, "in array check - passing unsorted list");
equal(u.hasQuery('list', [/ne$/], true), true, "in array check - passing RegExp");

// comparison function
equal(u.hasQuery('string', function(value, name, data) {
equal(value, "bar", "Function check - param value");
equal(name, "string", "Function check - param name");
equal(typeof data, "object", "Function check - param data");
return true;
}), true, "Function check - passing true");
equal(u.hasQuery('string', function(value, name, data) {
return false;
}), false, "Function check - passing false");
});

module("normalizing");
test("normalize", function() {
Expand Down

0 comments on commit cc18c99

Please sign in to comment.