Skip to content

Commit

Permalink
Mode compatible with Node.js
Browse files Browse the repository at this point in the history
Added travis CI integration
  • Loading branch information
davidgtonge committed Feb 2, 2012
1 parent d94b14f commit 915aaeb
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 47 deletions.
3 changes: 3 additions & 0 deletions .npmignore
@@ -0,0 +1,3 @@
.idea/
.git/
node_modules/
3 changes: 3 additions & 0 deletions .travis.yml
@@ -0,0 +1,3 @@
language: node_js
node_js:
- 0.6
8 changes: 7 additions & 1 deletion Cakefile
Expand Up @@ -24,4 +24,10 @@ task 'uglify', 'Minify and obfuscate', ->
ast = pro.ast_squeeze ast # get an AST with compression optimizations ast = pro.ast_squeeze ast # get an AST with compression optimizations
final_code = pro.gen_code ast # compressed code here final_code = pro.gen_code ast # compressed code here


fs.writeFile 'js/backbone-query.min.js', final_code fs.writeFile 'js/backbone-query.min.js', final_code

task "test", "Test the code", ->
path = require 'path'
reporter = require('nodeunit').reporters.default

reporter.run ["test/backbone-query-test.js"]
33 changes: 18 additions & 15 deletions js/backbone-query.js
Expand Up @@ -6,7 +6,7 @@ May be freely distributed according to MIT license.
*/ */


(function() { (function() {
var and_iterator, array_intersection, get_cache, get_models, get_sorted_models, iterator, or_iterator, page_models, parse_query, process_query, sort_models, test_attr, test_query_value, var array_intersection, get_cache, get_models, get_sorted_models, iterator, page_models, parse_query, process_query, sort_models, test_attr, test_query_value,
__indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };


array_intersection = function(arrays) { array_intersection = function(arrays) {
Expand Down Expand Up @@ -88,10 +88,10 @@ May be freely distributed according to MIT license.
} }
}; };


iterator = function(collection, query, andOr) { iterator = function(collection, query, andOr, filterReject) {
var parsed_query; var parsed_query;
parsed_query = parse_query(query); parsed_query = parse_query(query);
return collection.filter(function(model) { return collection[filterReject](function(model) {
var attr, q, test, _i, _len; var attr, q, test, _i, _len;
for (_i = 0, _len = parsed_query.length; _i < _len; _i++) { for (_i = 0, _len = parsed_query.length; _i < _len; _i++) {
q = parsed_query[_i]; q = parsed_query[_i];
Expand Down Expand Up @@ -149,26 +149,18 @@ May be freely distributed according to MIT license.
}); });
}; };


and_iterator = function(collection, query) {
return iterator(collection, query, false);
};

or_iterator = function(collection, query) {
return iterator(collection, query, true);
};

process_query = { process_query = {
$and: function(collection, query) { $and: function(collection, query) {
return and_iterator(collection, query); return iterator(collection, query, false, "filter");
}, },
$or: function(collection, query) { $or: function(collection, query) {
return or_iterator(collection, query); return iterator(collection, query, true, "filter");
}, },
$nor: function(collection, query) { $nor: function(collection, query) {
return _.difference(collection.models, or_iterator(collection, query)); return iterator(collection, query, true, "reject");
}, },
$not: function(collection, query) { $not: function(collection, query) {
return _.difference(collection.models, and_iterator(collection, query)); return iterator(collection, query, false, "reject");
} }
}; };


Expand Down Expand Up @@ -244,6 +236,13 @@ May be freely distributed according to MIT license.
return sliced_models; return sliced_models;
}; };


if (typeof require !== 'undefined') {
if (typeof _ === "undefined" || _ === null) _ = require('underscore');
if (typeof Backbone === "undefined" || Backbone === null) {
Backbone = require('backbone');
}
}

Backbone.QueryCollection = Backbone.Collection.extend({ Backbone.QueryCollection = Backbone.Collection.extend({
query: function(query, options) { query: function(query, options) {
var models; var models;
Expand All @@ -261,4 +260,8 @@ May be freely distributed according to MIT license.
} }
}); });


if (typeof exports !== "undefined") {
exports.QueryCollection = Backbone.QueryCollection;
}

}).call(this); }).call(this);
22 changes: 22 additions & 0 deletions package.json
@@ -0,0 +1,22 @@
{
"name": "backbone-query"
, "description": "Lightweight Query API for Backbone Collections"
, "version": "0.1.1"
, "author": "Dave Tonge <dave@simplecreativity.co.uk> (https://github.com/davidgtonge)"
, "tags": ["backbone", "underscore", "mongo", "query"]
, "main": "./js/backbone-query"
, "repository": {
"type": "git"
, "url": "https://davidgtonge@github.com/davidgtonge/backbone_query.git"
}
, "dependencies": {
"backbone": ">=0.5.x"
, "underscore": ">=1.1.x"
}
, "devDependencies": {
"qunit": "0.1.x"
}
, "scripts": {
"test": "cake test"
}
}
50 changes: 26 additions & 24 deletions src/backbone-query.coffee
Expand Up @@ -40,27 +40,27 @@ parse_query = (raw_query) ->
# Tests query value, to ensure that it is of the correct type # Tests query value, to ensure that it is of the correct type
test_query_value = (type, value) -> test_query_value = (type, value) ->
switch type switch type
when "$in","$nin","$all", "$any" then _(value).isArray() when "$in","$nin","$all", "$any" then _(value).isArray()
when "$size" then _(value).isNumber() when "$size" then _(value).isNumber()
when "$regex" then _(value).isRegExp() when "$regex" then _(value).isRegExp()
when "$like" then _(value).isString() when "$like" then _(value).isString()
when "$between" then _(value).isArray() and (value.length is 2) when "$between" then _(value).isArray() and (value.length is 2)
when "$cb" then _(value).isFunction() when "$cb" then _(value).isFunction()
else true else true


test_attr = (type, value) -> test_attr = (type, value) ->
switch type switch type
when "$like", "$regex" then _(value).isString() when "$like", "$regex" then _(value).isString()
when "$contains", "$all", "$any" then _(value).isArray() when "$contains", "$all", "$any" then _(value).isArray()
when "$size" then _(value).isArray() or _(value).isString() when "$size" then _(value).isArray() or _(value).isString()
when "$in", "$nin" then value? when "$in", "$nin" then value?
else true else true


# The main iterator that actually applies the query # The main iterator that actually applies the query
iterator = (collection, query, andOr) -> iterator = (collection, query, andOr, filterReject) ->
parsed_query = parse_query query parsed_query = parse_query query
# The collections filter method is used to iterate through each model in the collection # The collections filter or reject method is used to iterate through each model in the collection
collection.filter (model) -> collection[filterReject] (model) ->
# For each model in the collection, iterate through the supplied queries # For each model in the collection, iterate through the supplied queries
for q in parsed_query for q in parsed_query
# Retrieve the attribute value from the model # Retrieve the attribute value from the model
Expand Down Expand Up @@ -94,15 +94,13 @@ iterator = (collection, query, andOr) ->
# For an "and" query, if all the queries are true, then we return true # For an "and" query, if all the queries are true, then we return true
not andOr not andOr


and_iterator = (collection, query) -> iterator collection, query, false
or_iterator = (collection, query) -> iterator collection, query, true


# A object with or, and, nor and not methods # A object with or, and, nor and not methods
process_query = process_query =
$and: (collection, query) -> and_iterator collection, query $and: (collection, query) -> iterator collection, query, false, "filter"
$or: (collection, query) -> or_iterator collection, query $or: (collection, query) -> iterator collection, query, true, "filter"
$nor: (collection, query) -> _.difference collection.models, (or_iterator collection, query) $nor: (collection, query) -> iterator collection, query, true, "reject"
$not: (collection, query) -> _.difference collection.models, (and_iterator collection, query) $not: (collection, query) -> iterator collection, query, false, "reject"


get_cache = (collection, query, options) -> get_cache = (collection, query, options) ->
# Convert the query to a string to use as a key in the cache # Convert the query to a string to use as a key in the cache
Expand All @@ -123,7 +121,7 @@ get_models = (collection, query) ->
# Iterate through the query keys to check for any of the compound methods # Iterate through the query keys to check for any of the compound methods
compound_query = _(query).chain().keys().intersection(["$or", "$and", "$nor", "$not"]).value() compound_query = _(query).chain().keys().intersection(["$or", "$and", "$nor", "$not"]).value()


(switch compound_query.length switch compound_query.length
# If no compound methods are found then use the "and" iterator # If no compound methods are found then use the "and" iterator
when 0 then process_query.$and collection, query when 0 then process_query.$and collection, query


Expand All @@ -138,7 +136,7 @@ get_models = (collection, query) ->
process_query[type] collection, query[type]) process_query[type] collection, query[type])


# A modified form of Underscores Intersection is used to find the models that appear in all the result sets # A modified form of Underscores Intersection is used to find the models that appear in all the result sets
array_intersection results) array_intersection results


# Gets the results and optionally sorts them # Gets the results and optionally sorts them
get_sorted_models = (collection, query, options) -> get_sorted_models = (collection, query, options) ->
Expand Down Expand Up @@ -179,8 +177,9 @@ page_models = (models, options) ->


sliced_models sliced_models



unless typeof require is 'undefined'

_ ?= require 'underscore'
Backbone ?= require 'backbone'


Backbone.QueryCollection = Backbone.Collection.extend Backbone.QueryCollection = Backbone.Collection.extend


Expand All @@ -201,4 +200,7 @@ Backbone.QueryCollection = Backbone.Collection.extend


# Helper method to reset the query cache # Helper method to reset the query cache
# Defined as a separate method to make it easy to bind to collection's change/add/remove events # Defined as a separate method to make it easy to bind to collection's change/add/remove events
reset_query_cache: -> @_query_cache = {} reset_query_cache: -> @_query_cache = {}

unless typeof exports is "undefined"
exports.QueryCollection = Backbone.QueryCollection
20 changes: 18 additions & 2 deletions test/backbone-query-test.coffee
@@ -1,7 +1,23 @@
module "Backbone Query" if typeof require isnt "undefined"
{QueryCollection} = require "../js/backbone-query.js"
else
QueryCollection = Backbone.QueryCollection

# Helper functions that turn Qunit tests into nodeunit tests
equals = []

test ?= (name, test_cb) ->
exports[name] = (testObj) ->
equals = []
test_cb()
for result in equals
testObj.equal result[0], result[1]
testObj.done()

equal ?= (real, expected) -> equals.push [real, expected]


create = -> create = ->
new Backbone.QueryCollection [ new QueryCollection [
{title:"Home", colors:["red","yellow","blue"], likes:12, featured:true, content: "Dummy content about coffeescript"} {title:"Home", colors:["red","yellow","blue"], likes:12, featured:true, content: "Dummy content about coffeescript"}
{title:"About", colors:["red"], likes:2, featured:true, content: "dummy content about javascript"} {title:"About", colors:["red"], likes:2, featured:true, content: "dummy content about javascript"}
{title:"Contact", colors:["red","blue"], likes:20, content: "Dummy content about PHP"} {title:"Contact", colors:["red","blue"], likes:20, content: "Dummy content about PHP"}
Expand Down
35 changes: 31 additions & 4 deletions test/backbone-query-test.js
@@ -1,10 +1,37 @@
(function() { (function() {
var create; var QueryCollection, create, equals;


module("Backbone Query"); if (typeof require !== "undefined") {
QueryCollection = require("../js/backbone-query.js").QueryCollection;
} else {
QueryCollection = Backbone.QueryCollection;
}

equals = [];

if (typeof test === "undefined" || test === null) {
test = function(name, test_cb) {
return exports[name] = function(testObj) {
var result, _i, _len;
test_cb();
for (_i = 0, _len = equals.length; _i < _len; _i++) {
result = equals[_i];
testObj.equal(result[0], result[1]);
}
equals = [];
return testObj.done();
};
};
}

if (typeof equal === "undefined" || equal === null) {
equal = function(real, expected) {
return equals.push([real, expected]);
};
}


create = function() { create = function() {
return new Backbone.QueryCollection([ return new QueryCollection([
{ {
title: "Home", title: "Home",
colors: ["red", "yellow", "blue"], colors: ["red", "yellow", "blue"],
Expand Down
2 changes: 1 addition & 1 deletion test/index.html
Expand Up @@ -11,7 +11,7 @@
<script src="../js/backbone-query.js"></script> <script src="../js/backbone-query.js"></script>
</head> </head>
<body> <body>
<h1 id="qunit-header">backbone-forms tests</h1> <h1 id="qunit-header">backbone-query tests</h1>
<h2 id="qunit-banner"></h2> <h2 id="qunit-banner"></h2>
<div id="qunit-testrunner-toolbar"></div> <div id="qunit-testrunner-toolbar"></div>
<h2 id="qunit-userAgent"></h2> <h2 id="qunit-userAgent"></h2>
Expand Down

0 comments on commit 915aaeb

Please sign in to comment.