Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

First commit of major refactor

  • Loading branch information...
commit bfb0ca55a77c4d997c3da04cde9e787ea1cb96ec 1 parent 2e1637d
@davidgtonge authored
View
2  .travis.yml
@@ -6,4 +6,4 @@ before_script:
- "npm install"
script:
- - "node_modules/.bin/cake test"
+ - "node_modules/.bin/mocha"
View
240 Cakefile
@@ -1,15 +1,231 @@
-fs = require 'fs'
-{exec} = require 'child_process'
+# ** Cakefile Template ** is a Template for a common Cakefile that you may use in a coffeescript nodejs project.
+#
+# It comes baked in with 5 tasks:
+#
+# * build - compiles your src directory to your lib directory
+# * watch - watches any changes in your src directory and automatically compiles to the lib directory
+# * test - runs mocha test framework, you can edit this task to use your favorite test framework
+# * docs - generates annotated documentation using docco
+# * clean - clean generated .js files
+files = [
+ 'lib'
+ 'src'
+]
-task 'build', 'Build JS files from Coffee sources', ->
+fs = require 'fs'
+{print} = require 'util'
+{spawn, exec} = require 'child_process'
- exec 'coffee -c -o js/ src/', (err, stdout, stderr) ->
- throw err if err
- console.log stdout + stderr
+try
+ which = require('which').sync
+catch err
+ if process.platform.match(/^win/)?
+ console.log 'WARNING: the which module is required for windows\ntry: npm install which'
+ which = null
- exec 'coffee -c test/backbone-query-test.coffee', (err, stdout, stderr) ->
- throw err if err
- console.log stdout + stderr
+# ANSI Terminal Colors
+bold = '\x1b[0;1m'
+green = '\x1b[0;32m'
+reset = '\x1b[0m'
+red = '\x1b[0;31m'
+
+# Cakefile Tasks
+#
+# ## *docs*
+#
+# Generate Annotated Documentation
+#
+# <small>Usage</small>
+#
+# ```
+# cake docs
+# ```
+task 'docs', 'generate documentation', -> docco()
+
+# ## *build*
+#
+# Builds Source
+#
+# <small>Usage</small>
+#
+# ```
+# cake build
+# ```
+task 'build', 'compile source', -> build -> log ":)", green
+
+# ## *watch*
+#
+# Builds your source whenever it changes
+#
+# <small>Usage</small>
+#
+# ```
+# cake watch
+# ```
+task 'watch', 'compile and watch', -> build true, -> log ":-)", green
+
+# ## *test*
+#
+# Runs your test suite.
+#
+# <small>Usage</small>
+#
+# ```
+# cake test
+# ```
+task 'test', 'run tests', -> build -> mocha -> log ":)", green
+
+# ## *clean*
+#
+# Cleans up generated js files
+#
+# <small>Usage</small>
+#
+# ```
+# cake clean
+# ```
+task 'clean', 'clean generated files', -> clean -> log ";)", green
+
+
+# Internal Functions
+#
+# ## *walk*
+#
+# **given** string as dir which represents a directory in relation to local directory
+# **and** callback as done in the form of (err, results)
+# **then** recurse through directory returning an array of files
+#
+# Examples
+#
+# ``` coffeescript
+# walk 'src', (err, results) -> console.log results
+# ```
+walk = (dir, done) ->
+ results = []
+ fs.readdir dir, (err, list) ->
+ return done(err, []) if err
+ pending = list.length
+ return done(null, results) unless pending
+ for name in list
+ file = "#{dir}/#{name}"
+ try
+ stat = fs.statSync file
+ catch err
+ stat = null
+ if stat?.isDirectory()
+ walk file, (err, res) ->
+ results.push name for name in res
+ done(null, results) unless --pending
+ else
+ results.push file
+ done(null, results) unless --pending
+
+# ## *log*
+#
+# **given** string as a message
+# **and** string as a color
+# **and** optional string as an explanation
+# **then** builds a statement and logs to console.
+#
+log = (message, color, explanation) -> console.log color + message + reset + ' ' + (explanation or '')
+
+# ## *launch*
+#
+# **given** string as a cmd
+# **and** optional array and option flags
+# **and** optional callback
+# **then** spawn cmd with options
+# **and** pipe to process stdout and stderr respectively
+# **and** on child process exit emit callback if set and status is 0
+launch = (cmd, options=[], callback) ->
+ cmd = which(cmd) if which
+ app = spawn cmd, options
+ app.stdout.pipe(process.stdout)
+ app.stderr.pipe(process.stderr)
+ app.on 'exit', (status) -> callback?() if status is 0
+
+# ## *build*
+#
+# **given** optional boolean as watch
+# **and** optional function as callback
+# **then** invoke launch passing coffee command
+# **and** defaulted options to compile src to lib
+build = (watch, callback) ->
+ if typeof watch is 'function'
+ callback = watch
+ watch = false
+
+ options = ['-c', '-b', '-o' ]
+ options = options.concat files
+ options.unshift '-w' if watch
+ launch 'coffee', options, callback
+
+# ## *unlinkIfCoffeeFile*
+#
+# **given** string as file
+# **and** file ends in '.coffee'
+# **then** convert '.coffee' to '.js'
+# **and** remove the result
+unlinkIfCoffeeFile = (file) ->
+ if file.match /\.coffee$/
+ fs.unlink file.replace(/\.coffee$/, '.js')
+ true
+ else false
+
+# ## *clean*
+#
+# **given** optional function as callback
+# **then** loop through files variable
+# **and** call unlinkIfCoffeeFile on each
+clean = (callback) ->
+ try
+ for file in files
+ unless unlinkIfCoffeeFile file
+ walk file, (err, results) ->
+ for f in results
+ unlinkIfCoffeeFile f
+
+ callback?()
+ catch err
+
+ # ## *moduleExists*
+ #
+ # **given** name for module
+ # **when** trying to require module
+ # **and** not found
+ # **then* print not found message with install helper in red
+ # **and* return false if not found
+moduleExists = (name) ->
+ try
+ require name
+ catch err
+ log "#{name} required: npm install #{name}", red
+ false
+
+
+# ## *mocha*
+#
+# **given** optional array of option flags
+# **and** optional function as callback
+# **then** invoke launch passing mocha command
+mocha = (options, callback) ->
+ #if moduleExists('mocha')
+ if typeof options is 'function'
+ callback = options
+ options = []
+ # add coffee directive
+ options.push '--coffee'
+ options.push 'coffee:coffee-script'
+
+ launch 'mocha', options, callback
+
+# ## *docco*
+#
+# **given** optional function as callback
+# **then** invoke launch passing docco command
+docco = (callback) ->
+ #if moduleExists('docco')
+ walk 'src', (err, files) -> launch 'docco', files, callback
task 'uglify', 'Minify and obfuscate', ->
uglify = require 'uglify-js'
@@ -24,9 +240,3 @@ task 'uglify', 'Minify and obfuscate', ->
final_code = pro.gen_code ast # compressed code here
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"]
View
65 js/backbone-query.js
@@ -1,3 +1,4 @@
+// Generated by CoffeeScript 1.3.1
/*
Backbone Query - A lightweight query API for Backbone Collections
@@ -5,9 +6,10 @@ Backbone Query - A lightweight query API for Backbone Collections
May be freely distributed according to MIT license.
*/
+
(function() {
- var detect, filter, get_cache, get_models, get_sorted_models, iterator, page_models, parse_query, perform_query, process_query, reject, sort_models, test_model_attribute, 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; };
+ var Backbone, detect, filter, get_cache, get_models, get_sorted_models, iterator, page_models, parse_query, perform_query, process_query, reject, sort_models, test_model_attribute, test_query_value, _,
+ __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
parse_query = function(raw_query) {
var key, o, q, query_param, type, value, _results;
@@ -44,7 +46,9 @@ May be freely distributed according to MIT license.
o.type = "$equal";
o.value = query_param;
}
- if (o.type === "$equal" && _(o.value).isObject()) o.type = "$oEqual";
+ if (o.type === "$equal" && _(o.value).isObject()) {
+ o.type = "$oEqual";
+ }
_results.push(o);
}
return _results;
@@ -159,7 +163,9 @@ May be freely distributed according to MIT license.
iterator = function(models, query, andOr, filterFunction, subQuery) {
var parsed_query;
- if (subQuery == null) subQuery = false;
+ if (subQuery == null) {
+ subQuery = false;
+ }
parsed_query = subQuery ? query : parse_query(query);
return filterFunction(models, function(model) {
var attr, q, test, _i, _len;
@@ -176,8 +182,12 @@ May be freely distributed according to MIT license.
}
})();
test = test_model_attribute(q.type, attr);
- if (test) test = perform_query(q.type, q.value, attr, model, q.key);
- if (andOr === test) return andOr;
+ if (test) {
+ test = perform_query(q.type, q.value, attr, model, q.key);
+ }
+ if (andOr === test) {
+ return andOr;
+ }
}
return !andOr;
});
@@ -188,7 +198,9 @@ May be freely distributed according to MIT license.
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
val = array[_i];
- if (test(val)) _results.push(val);
+ if (test(val)) {
+ _results.push(val);
+ }
}
return _results;
};
@@ -198,7 +210,9 @@ May be freely distributed according to MIT license.
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
val = array[_i];
- if (!test(val)) _results.push(val);
+ if (!test(val)) {
+ _results.push(val);
+ }
}
return _results;
};
@@ -207,7 +221,9 @@ May be freely distributed according to MIT license.
var val, _i, _len;
for (_i = 0, _len = array.length; _i < _len; _i++) {
val = array[_i];
- if (test(val)) return true;
+ if (test(val)) {
+ return true;
+ }
}
return false;
};
@@ -256,7 +272,9 @@ May be freely distributed according to MIT license.
get_sorted_models = function(collection, query, options) {
var models;
models = get_models(collection, query);
- if (options.sortBy) models = sort_models(models, options);
+ if (options.sortBy) {
+ models = sort_models(models, options);
+ }
return models;
};
@@ -268,7 +286,9 @@ May be freely distributed according to MIT license.
} else if (_(options.sortBy).isFunction()) {
models = _(models).sortBy(options.sortBy);
}
- if (options.order === "desc") models = models.reverse();
+ if (options.order === "desc") {
+ models = models.reverse();
+ }
return models;
};
@@ -291,26 +311,33 @@ May be freely distributed according to MIT license.
};
if (typeof require !== 'undefined') {
- if (typeof _ === "undefined" || _ === null) _ = require('underscore');
- if (typeof Backbone === "undefined" || Backbone === null) {
- Backbone = require('backbone');
- }
+ _ = require('underscore');
+ Backbone = require('backbone');
}
Backbone.QueryCollection = Backbone.Collection.extend({
query: function(query, options) {
var models;
- if (options == null) options = {};
+ if (options == null) {
+ options = {};
+ }
if (options.cache) {
models = get_cache(this, query, options);
} else {
models = get_sorted_models(this, query, options);
}
- if (options.limit) models = page_models(models, options);
+ if (options.limit) {
+ models = page_models(models, options);
+ }
return models;
},
- where: function(params, options) {
- if (options == null) options = {};
+ find_one: function(query) {
+ return this.query(query)[0];
+ },
+ where_by: function(params, options) {
+ if (options == null) {
+ options = {};
+ }
return new this.constructor(this.query(params, options));
},
reset_query_cache: function() {
View
6 package.json
@@ -1,7 +1,7 @@
{
"name": "backbone-query"
, "description": "Lightweight Query API for Backbone Collections"
- , "version": "0.1.2"
+ , "version": "0.2.0"
, "author": "Dave Tonge <dave@simplecreativity.co.uk> (https://github.com/davidgtonge)"
, "tags": ["backbone", "underscore", "mongo", "query"]
, "main": "./js/backbone-query"
@@ -15,10 +15,10 @@
}
, "devDependencies": {
"coffee-script" : ">=1.x.x"
- ,"nodeunit": "0.6.x"
+ ,"moacha": ""
,"uglify-js": "1.2.2"
}
, "scripts": {
- "test": "cake test"
+ "test": "mocha"
}
}
View
222 src/backbone-query.coffee
@@ -4,41 +4,106 @@ Backbone Query - A lightweight query API for Backbone Collections
May be freely distributed according to MIT license.
###
-# This function parses the query and converts it into an array of objects.
-# Each object has a key (model property), type (query type - $gt, $like...) and value (mixed).
-parse_query = (raw_query) ->
- (for key, query_param of raw_query
- o = {key}
- # Test for Regexs as they can be supplied without an operator
- if _.isRegExp(query_param)
- o.type = "$regex"
- o.value = query_param
- # If the query paramater is an object then extract the key and value
- else if _(query_param).isObject() and not _(query_param).isArray()
- for type, value of query_param
- # Before adding the query, its value is checked to make sure it is the right type
- if test_query_value type, value
- o.type = type
- switch type
- when "$elemMatch", "$relationMatch"
- o.value = parse_query value
- when "$computed"
- q = {}
- q[key] = value
- o.value = parse_query q
- else
- o.value = value
- # If the query_param is not an object or a regexp then revert to the default operator: $equal
- else
- o.type = "$equal"
- o.value = query_param
- # For "$equal" queries with arrays or objects we need to perform a deep equal
- if o.type is "$equal" and _(o.value).isObject() then o.type = "$oEqual"
+### UTILS ###
+
+# Custom Filter / Reject methods faster than underscore methods as use for loops
+# http://jsperf.com/filter-vs-for-loop2
+filter = (array, test) -> (val for val in array when test val)
+reject = (array, test) -> (val for val in array when not test val)
+detect = (array, test) ->
+ for val in array
+ return true if test val
+ false
+
+# Utility Function to turn a list of values into an object
+makeObj = (args...)->
+ o = {}
+ current = o
+ while args.length
+ key = args.shift()
+ val = (if args.length is 1 then args.shift() else {})
+ current = current[key] = val
+ o
+
+# Get the type as a string
+getType = (item) ->
+ return "$regex" if _.isRegExp(item)
+ return "$date" if _.isDate(item)
+ return "object" if _.isObject(item) and not _.isArray(item)
+ return "array" if _.isArray(item)
+ return "string" if _.isString(item)
+ return "number" if _.isNumber(item)
+ return "boolean" if _.isBoolean(item)
+ return "function" if _.isFunction(item)
+ false
+
+###
+Function to parse raw queries
+@param {mixed} raw query
+@return {array} parsed query
+
+Allows queries of the following forms:
+query
+ name: "test"
+ id: $gte: 10
+
+query [
+ {name:"test"}
+ {id:$gte:10}
+]
+###
+parseQuery = (rawQuery) ->
+
+ if _.isArray(rawQuery)
+ queryArray = rawQuery
+ else
+ queryArray = (makeObj(key, val) for own key, val of rawQuery)
+
+ (for query in queryArray
+ for own key, queryParam of query
+ o = {key}
+ paramType = getType(queryParam)
+ switch paramType
+ # Test for Regexs and Dates as they can be supplied without an operator
+ when "$regex", "$date"
+ o.type = paramType
+ o.value = queryParam
+
+ # If the query paramater is an object then extract the key and value
+ when "object"
+ if key in ["$and", "$or", "$nor", "$not"]
+ o.value = parseQuery(queryParam)
+ o.type = key
+ o.key = null
+ else
+ for type, value of queryParam
+ # Before adding the query, its value is checked to make sure it is the right type
+ if testQueryValue type, value
+ o.type = type
+ switch type
+ when "$elemMatch", "$relationMatch"
+ o.value = parseQuery value
+ when "$computed"
+ q = makeObj(key,value)
+ o.value = parseQuery q
+ else
+ o.value = value
+
+ # If the query_param is not an object or a regexp then revert to the default operator: $equal
+ else
+ o.type = "$equal"
+ o.value = queryParam
+
+ # For "$equal" queries with arrays or objects we need to perform a deep equal
+ if (o.type is "$equal") and (paramType in ["object","array"])
+ o.type = "$oEqual"
o)
+
+
# Tests query value, to ensure that it is of the correct type
-test_query_value = (type, value) ->
+testQueryValue = (type, value) ->
switch type
when "$in","$nin","$all", "$any" then _(value).isArray()
when "$size" then _(value).isNumber()
@@ -49,7 +114,7 @@ test_query_value = (type, value) ->
else true
# Test each attribute that is being tested to ensure that is of the correct type
-test_model_attribute = (type, value) ->
+testModelAttribute = (type, value) ->
switch type
when "$like", "$likeI", "$regex" then _(value).isString()
when "$contains", "$all", "$any", "$elemMatch" then _(value).isArray()
@@ -59,7 +124,7 @@ test_model_attribute = (type, value) ->
else true
# Perform the actual query logic for each query and each model/attribute
-perform_query = (type, value, attr, model, key) ->
+performQuery = (type, value, attr, model, key) ->
switch type
when "$equal"
# If the attrubute is an array then search for the query value in the array the same as Mongo
@@ -85,25 +150,27 @@ perform_query = (type, value, attr, model, key) ->
when "$elemMatch" then iterator attr, value, false, detect, "elemMatch"
when "$relationMatch" then iterator attr.models, value, false, detect, "relationMatch"
when "$computed" then iterator [model], value, false, detect, "computed"
+ when "$and", "$or", "$nor", "$not"
+ (processQuery[type]([model], value)).length
else false
# The main iterator that actually applies the query
iterator = (models, query, andOr, filterFunction, subQuery = false) ->
- parsed_query = if subQuery then query else parse_query query
+ parsedQuery = if subQuery then query else parseQuery query
# The collections filter or reject method is used to iterate through each model in the collection
filterFunction models, (model) ->
# For each model in the collection, iterate through the supplied queries
- for q in parsed_query
+ for q in parsedQuery
# Retrieve the attribute value from the model
attr = switch subQuery
when "elemMatch" then model[q.key]
when "computed" then model[q.key]()
else model.get(q.key)
# Check if the attribute value is the right type (some operators need a string, or an array)
- test = test_model_attribute(q.type, attr)
+ test = testModelAttribute(q.type, attr)
# If the attribute test is true, perform the query
- if test then test = perform_query q.type, q.value, attr, model, q.key
+ if test then test = performQuery q.type, q.value, attr, model, q.key
# If the query is an "or" query than as soon as a match is found we return "true"
# Whereas if the query is an "and" query then we return "false" as soon as a match isn't found.
return andOr if andOr is test
@@ -112,17 +179,10 @@ iterator = (models, query, andOr, filterFunction, subQuery = false) ->
# For an "and" query, if all the queries are true, then we return true
not andOr
-# Custom Filter / Reject methods faster than underscore methods as use for loops
-# http://jsperf.com/filter-vs-for-loop2
-filter = (array, test) -> (val for val in array when test val)
-reject = (array, test) -> (val for val in array when not test val)
-detect = (array, test) ->
- for val in array
- return true if test val
- false
+
# An object with or, and, nor and not methods
-process_query =
+processQuery =
$and: (models, query) -> iterator models, query, false, filter
$or: (models, query) -> iterator models, query, true, filter
$nor: (models, query) -> iterator models, query, true, reject
@@ -132,51 +192,61 @@ process_query =
# This method attempts to retrieve the result from the cache.
# If no match is found in the cache, then the query is run and
# the results are saved in the cache
-get_cache = (collection, query, options) ->
+getCache = (collection, query, options) ->
# Convert the query to a string to use as a key in the cache
- query_string = JSON.stringify query
+ queryString = JSON.stringify query
# Create cache if doesn't exist
- cache = collection._query_cache ?= {}
+ cache = collection._queryCache ?= {}
# Retrieve cached results
- models = cache[query_string]
+ models = cache[queryString]
# If no results are retrieved then use the get_models method and cache the result
unless models
- models = get_sorted_models collection, query, options
- cache[query_string] = models
+ models = getSortedModels collection, query, options
+ cache[queryString] = models
# Return the results
models
# This method get the unsorted results
-get_models = (collection, query) ->
+getModels = (collection, query) ->
# Iterate through the query keys to check for any of the compound methods
# The resulting array will have "$and" and "$not" first as it is better to use these
# operators first when performing a compound query as they are likely to return less results
- compound_query = _.intersection ["$and", "$not", "$or", "$nor"], _(query).keys()
-
- # Assign the collections models to a local variable to use in the following switch
- models = collection.models
+ queryKeys = _(query).keys()
+ compoundKeys = ["$and", "$not", "$or", "$nor"]
+ compoundQuery = _.intersection compoundKeys, queryKeys
- if compound_query.length is 0
+ if compoundQuery.length is 0
# If no compound methods are found then use the "and" iterator
- process_query.$and models, query
+ processQuery.$and collection.models, query
else
- # Else iterate through the compound methods using underscore reduce
+ # Detect if there is an implicit $and compundQuery operator
+ if compoundQuery.length isnt queryKeys.length
+ # Add the and compund query operator (with a sanity check that it doesn't exist)
+ if "$and" not in compoundQuery
+ query.$and = {}
+ compoundQuery.unshift "$and"
+ for own key, val of query when key not in compoundKeys
+ query.$and[key] = val
+ delete query[key]
+
+
+ # Iterate through the compound methods using underscore reduce
# The reduce iterator takes an array of models, performs the query and returns
# the matched models for the next query
- reduce_iterator = (memo, query_type) ->
- process_query[query_type] memo, query[query_type]
+ reduceIterator = (memo, queryType) ->
+ processQuery[queryType] memo, query[queryType]
- _.reduce compound_query, reduce_iterator, models
+ _.reduce compoundQuery, reduceIterator, collection.models
# Gets the results and optionally sorts them
-get_sorted_models = (collection, query, options) ->
- models = get_models collection, query
- if options.sortBy then models = sort_models models, options
+getSortedModels = (collection, query, options) ->
+ models = getModels collection, query
+ if options.sortBy then models = sortModels models, options
models
# Sorts models either be a model attribute or with a callback
-sort_models = (models, options) ->
+sortModels = (models, options) ->
# If the sortBy param is a string then we sort according to the model attribute with that string as a key
if _(options.sortBy).isString()
models = _(models).sortBy (model) -> model.get(options.sortBy)
@@ -191,7 +261,7 @@ sort_models = (models, options) ->
models
# Slices the results set according to the supplied options
-page_models = (models, options) ->
+pageModels = (models, options) ->
# Expects object in the form: {limit: num, offset: num, page: num, pager:callback}
if options.offset then start = options.offset
else if options.page then start = (options.page - 1) * options.limit
@@ -210,8 +280,8 @@ page_models = (models, options) ->
# If used on the server, then Backbone and Underscore are loaded as modules
unless typeof require is 'undefined'
- _ ?= require 'underscore'
- Backbone ?= require 'backbone'
+ _ = require 'underscore'
+ Backbone = require 'backbone'
Backbone.QueryCollection = Backbone.Collection.extend
@@ -220,23 +290,25 @@ Backbone.QueryCollection = Backbone.Collection.extend
# Retrieve matching models using the supplied query
if options.cache
- models = get_cache @, query, options
+ models = getCache @, query, options
else
- models = get_sorted_models @, query, options
+ models = getSortedModels @, query, options
# If a limit param is specified than slice the results
- if options.limit then models = page_models models, options
+ if options.limit then models = pageModels models, options
# Return the results
models
+ findOne: (query) -> @query(query)[0]
+
# Where method wraps query and returns a new collection
- where: (params, options = {})->
+ whereBy: (params, options = {})->
new @constructor @query params, options
# 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
- reset_query_cache: -> @_query_cache = {}
+ resetQueryCache: -> @_queryCache = {}
# On the server the new Query Collection is added to exports
unless typeof exports is "undefined"
View
460 test/backbone-query-test.coffee
@@ -1,460 +0,0 @@
-
-if typeof require isnt "undefined"
- {QueryCollection} = require "../js/backbone-query.js"
- Backbone = require "backbone"
-else
- QueryCollection = window.Backbone.QueryCollection
- Backbone = window.Backbone
-
-# 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 = ->
- new QueryCollection [
- {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:"Contact", colors:["red","blue"], likes:20, content: "Dummy content about PHP"}
- ]
-
-
-test "Equals query", ->
- a = create()
- result = a.query title:"Home"
- equal result.length, 1
- equal result[0].get("title"), "Home"
-
- result = a.query colors: "blue"
- equal result.length, 2
-
- result = a.query colors: ["red", "blue"]
- equal result.length, 1
-
-
-
-test "Simple equals query (no results)", ->
- a = create()
- result = a.query title:"Homes"
- equal result.length, 0
-
-test "Simple equals query with explicit $equal", ->
- a = create()
- result = a.query title: {$equal: "About"}
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-test "$contains operator", ->
- a = create()
- result = a.query colors: {$contains: "blue"}
- equal result.length, 2
-
-test "$ne operator", ->
- a = create()
- result = a.query title: {$ne: "Home"}
- equal result.length, 2
-
-test "$lt operator", ->
- a = create()
- result = a.query likes: {$lt: 12}
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-test "$lte operator", ->
- a = create()
- result = a.query likes: {$lte: 12}
- equal result.length, 2
-
-test "$gt operator", ->
- a = create()
- result = a.query likes: {$gt: 12}
- equal result.length, 1
- equal result[0].get("title"), "Contact"
-
-test "$gte operator", ->
- a = create()
- result = a.query likes: {$gte: 12}
- equal result.length, 2
-
-test "$between operator", ->
- a = create()
- result = a.query likes: {$between: [1,5]}
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-test "$in operator", ->
- a = create()
- result = a.query title: {$in: ["Home","About"]}
- equal result.length, 2
-
-test "$in operator with wrong query value", ->
- a = create()
- result = a.query title: {$in: "Home"}
- equal result.length, 0
-
-test "$nin operator", ->
- a = create()
- result = a.query title: {$nin: ["Home","About"]}
- equal result.length, 1
- equal result[0].get("title"), "Contact"
-
-test "$all operator", ->
- a = create()
- result = a.query colors: {$all: ["red","blue"]}
- equal result.length, 2
-
-test "$all operator (wrong values)", ->
- a = create()
- result = a.query title: {$all: ["red","blue"]}
- equal result.length, 0
-
- result = a.query colors: {$all: "red"}
- equal result.length, 0
-
-test "$any operator", ->
- a = create()
- result = a.query colors: {$any: ["red","blue"]}
- equal result.length, 3
-
- result = a.query colors: {$any: ["yellow","blue"]}
- equal result.length, 2
-
-test "$size operator", ->
- a = create()
- result = a.query colors: {$size: 3}
- equal result.length, 1
- equal result[0].get("title"), "Home"
-
-test "$exists operator", ->
- a = create()
- result = a.query featured: {$exists: true}
- equal result.length, 2
-
-test "$has operator", ->
- a = create()
- result = a.query featured: {$exists: false}
- equal result.length, 1
- equal result[0].get("title"), "Contact"
-
-test "$like operator", ->
- a = create()
- result = a.query content: {$like: "javascript"}
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-test "$like operator 2", ->
- a = create()
- result = a.query content: {$like: "content"}
- equal result.length, 3
-
-test "$likeI operator", ->
- a = create()
- result = a.query content: {$likeI: "dummy"}
- equal result.length, 3
- result = a.query content: {$like: "dummy"}
- equal result.length, 1
-
-test "$regex", ->
- a = create()
- result = a.query content: {$regex: /javascript/gi}
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-test "$regex2", ->
- a = create()
- result = a.query content: {$regex: /dummy/}
- equal result.length, 1
-
-test "$regex3", ->
- a = create()
- result = a.query content: {$regex: /dummy/i}
- equal result.length, 3
-
-test "$regex4", ->
- a = create()
- result = a.query content: /javascript/i
- equal result.length, 1
-
-test "$cb - callback", ->
- a = create()
- result = a.query title: {$cb: (attr) -> attr.charAt(0).toLowerCase() is "c"}
- equal result.length, 1
- equal result[0].get("title"), "Contact"
-
-test "$cb - callback - checking 'this' is the model", ->
- a = create()
- result = a.query title:
- $cb: (attr) -> @get("title") is "Home"
- equal result.length, 1
- equal result[0].get("title"), "Home"
-
-test "$and operator", ->
- a = create()
- result = a.query likes: {$gt: 5}, colors: {$contains: "yellow"}
- equal result.length, 1
- equal result[0].get("title"), "Home"
-
-test "$and operator (explicit)", ->
- a = create()
- result = a.query $and: {likes: {$gt: 5}, colors: {$contains: "yellow"}}
- equal result.length, 1
- equal result[0].get("title"), "Home"
-
-test "$or operator", ->
- a = create()
- result = a.query $or: {likes: {$gt: 5}, colors: {$contains: "yellow"}}
- equal result.length, 2
-
-test "$nor operator", ->
- a = create()
- result = a.query $nor: {likes: {$gt: 5}, colors: {$contains: "yellow"}}
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-test "Compound Queries", ->
- a = create()
- result = a.query $and: {likes: {$gt: 5}}, $or: {content: {$like: "PHP"}, colors: {$contains: "yellow"}}
- equal result.length, 2
-
- result = a.query
- $and:
- likes: $lt: 15
- $or:
- content:
- $like: "Dummy"
- featured:
- $exists:true
- $not:
- colors: $contains: "yellow"
- equal result.length, 1
- equal result[0].get("title"), "About"
-
-
-
-test "Limit", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {limit:2}
- equal result.length, 2
-
-test "Offset", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {limit:2, offset:2}
- equal result.length, 1
-
-test "Page", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {limit:3, page:2}
- equal result.length, 0
-
-test "Sorder by model key", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {sortBy:"likes"}
- equal result.length, 3
- equal result[0].get("title"), "About"
- equal result[1].get("title"), "Home"
- equal result[2].get("title"), "Contact"
-
-test "Sorder by model key with descending order", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {sortBy:"likes", order:"desc"}
- equal result.length, 3
- equal result[2].get("title"), "About"
- equal result[1].get("title"), "Home"
- equal result[0].get("title"), "Contact"
-
-test "Sorder by function", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {sortBy: (model) -> model.get("title").charAt(2) }
- equal result.length, 3
- equal result[2].get("title"), "About"
- equal result[0].get("title"), "Home"
- equal result[1].get("title"), "Contact"
-
-test "cache", ->
- a = create()
- result = a.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal result.length, 3
- result = a.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal result.length, 3
- a.remove result[0]
- result = a.query {likes: {$gt: 1}}, {sortBy: (model) -> model.get("title").charAt(2) }
- equal result.length, 2
- result = a.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal result.length, 3
-
-test "cache with multiple collections", ->
- a = create()
- b = create()
- b.remove b.at(0)
- equal b.length, 2
- equal a.length, 3
-
- a_result = a.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal a_result.length, 3
- b_result = b.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal b_result.length, 2
-
- a.remove a_result[0]
- b.remove b_result[0]
-
- a_result = a.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal a_result.length, 3
- equal a.length, 2
- b_result = b.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal b_result.length, 2
- equal b.length, 1
-
- a.reset_query_cache()
- a_result = a.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal a_result.length, 2
- equal a.length, 2
-
- b_result = b.query {likes: {$gt: 1}}, {cache:true, sortBy: (model) -> model.get("title").charAt(2) }
- equal b_result.length, 2
- equal b.length, 1
-
-
-test "null attribute with various operators", ->
- a = create()
- result = a.query wrong_key: {$like: "test"}
- equal result.length, 0
- result = a.query wrong_key: {$regex: /test/}
- equal result.length, 0
- result = a.query wrong_key: {$contains: "test"}
- equal result.length, 0
- result = a.query wrong_key: {$all: [12,23]}
- equal result.length, 0
- result = a.query wrong_key: {$any: [12,23]}
- equal result.length, 0
- result = a.query wrong_key: {$size: 10}
- equal result.length, 0
- result = a.query wrong_key: {$in: [12,23]}
- equal result.length, 0
- result = a.query wrong_key: {$nin: [12,23]}
- equal result.length, 0
-
-test "Where method", ->
- a = create()
- result = a.where likes: $gt: 5
- equal result.length, 2
- equal result.models.length, result.length
-
-
-test "$computed", ->
- class testModel extends Backbone.Model
- full_name: -> "#{@get 'first_name'} #{@get 'last_name'}"
-
- a = new testModel
- first_name: "Dave"
- last_name: "Tonge"
- b = new testModel
- first_name: "John"
- last_name: "Smith"
- c = new QueryCollection [a,b]
-
- result = c.query
- full_name: $computed: "Dave Tonge"
-
- equal result.length, 1
- equal result[0].get("first_name"), "Dave"
-
- result = c.query
- full_name: $computed: $likeI: "n sm"
- equal result.length, 1
- equal result[0].get("first_name"), "John"
-
-
-test "$elemMatch", ->
- a = new QueryCollection [
- {title: "Home", comments:[
- {text:"I like this post"}
- {text:"I love this post"}
- {text:"I hate this post"}
- ]}
- {title: "About", comments:[
- {text:"I like this page"}
- {text:"I love this page"}
- {text:"I really like this page"}
- ]}
- ]
-
- b = new QueryCollection [
- {foo: [
- {shape: "square", color: "purple", thick: false}
- {shape: "circle", color: "red", thick: true}
- ]}
- {foo: [
- {shape: "square", color: "red", thick: true}
- {shape: "circle", color: "purple", thick: false}
- ]}
- ]
-
- text_search = {$likeI: "love"}
-
- result = a.query $or:
- comments:
- $elemMatch:
- text: text_search
- title: text_search
- equal result.length, 2
-
- result = a.query $or:
- comments:
- $elemMatch:
- text: /post/
- equal result.length, 1
-
- result = a.query $or:
- comments:
- $elemMatch:
- text: /post/
- title: /about/i
- equal result.length, 2
-
- result = a.query $or:
- comments:
- $elemMatch:
- text: /really/
- equal result.length, 1
-
- result = b.query
- foo:
- $elemMatch:
- shape:"square"
- color:"purple"
-
- equal result.length, 1
- #equal result[0].get("foo")[0].shape, "square"
- #equal result[0].get("foo")[0].color, "purple"
- #equal result[0].get("foo")[0].thick, false
-
-test "$any and $all", ->
- a = name: "test", tags1: ["red","yellow"], tags2: ["orange", "green", "red", "blue"]
- b = name: "test1", tags1: ["purple","blue"], tags2: ["orange", "red", "blue"]
- c = name: "test2", tags1: ["black","yellow"], tags2: ["green", "orange", "blue"]
- d = name: "test3", tags1: ["red","yellow","blue"], tags2: ["green"]
- e = new QueryCollection [a,b,c,d]
-
- result = e.query
- tags1: $any: ["red","purple"] # should match a, b, d
- tags2: $all: ["orange","green"] # should match a, c
-
- equal result.length, 1
- equal result[0].get("name"), "test"
-
-
-
-
-
-
-
-
-
View
991 test/backbone-query-test.js
@@ -1,991 +0,0 @@
-(function() {
- var Backbone, QueryCollection, create, equals,
- __hasProp = Object.prototype.hasOwnProperty,
- __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; };
-
- if (typeof require !== "undefined") {
- QueryCollection = require("../js/backbone-query.js").QueryCollection;
- Backbone = require("backbone");
- } else {
- QueryCollection = window.Backbone.QueryCollection;
- Backbone = window.Backbone;
- }
-
- equals = [];
-
- if (typeof test === "undefined" || test === null) {
- test = function(name, test_cb) {
- return exports[name] = function(testObj) {
- var result, _i, _len;
- equals = [];
- test_cb();
- for (_i = 0, _len = equals.length; _i < _len; _i++) {
- result = equals[_i];
- testObj.equal(result[0], result[1]);
- }
- return testObj.done();
- };
- };
- }
-
- if (typeof equal === "undefined" || equal === null) {
- equal = function(real, expected) {
- return equals.push([real, expected]);
- };
- }
-
- create = function() {
- return new QueryCollection([
- {
- 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: "Contact",
- colors: ["red", "blue"],
- likes: 20,
- content: "Dummy content about PHP"
- }
- ]);
- };
-
- test("Equals query", function() {
- var a, result;
- a = create();
- result = a.query({
- title: "Home"
- });
- equal(result.length, 1);
- equal(result[0].get("title"), "Home");
- result = a.query({
- colors: "blue"
- });
- equal(result.length, 2);
- result = a.query({
- colors: ["red", "blue"]
- });
- return equal(result.length, 1);
- });
-
- test("Simple equals query (no results)", function() {
- var a, result;
- a = create();
- result = a.query({
- title: "Homes"
- });
- return equal(result.length, 0);
- });
-
- test("Simple equals query with explicit $equal", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $equal: "About"
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("$contains operator", function() {
- var a, result;
- a = create();
- result = a.query({
- colors: {
- $contains: "blue"
- }
- });
- return equal(result.length, 2);
- });
-
- test("$ne operator", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $ne: "Home"
- }
- });
- return equal(result.length, 2);
- });
-
- test("$lt operator", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $lt: 12
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("$lte operator", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $lte: 12
- }
- });
- return equal(result.length, 2);
- });
-
- test("$gt operator", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 12
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Contact");
- });
-
- test("$gte operator", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gte: 12
- }
- });
- return equal(result.length, 2);
- });
-
- test("$between operator", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $between: [1, 5]
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("$in operator", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $in: ["Home", "About"]
- }
- });
- return equal(result.length, 2);
- });
-
- test("$in operator with wrong query value", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $in: "Home"
- }
- });
- return equal(result.length, 0);
- });
-
- test("$nin operator", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $nin: ["Home", "About"]
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Contact");
- });
-
- test("$all operator", function() {
- var a, result;
- a = create();
- result = a.query({
- colors: {
- $all: ["red", "blue"]
- }
- });
- return equal(result.length, 2);
- });
-
- test("$all operator (wrong values)", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $all: ["red", "blue"]
- }
- });
- equal(result.length, 0);
- result = a.query({
- colors: {
- $all: "red"
- }
- });
- return equal(result.length, 0);
- });
-
- test("$any operator", function() {
- var a, result;
- a = create();
- result = a.query({
- colors: {
- $any: ["red", "blue"]
- }
- });
- equal(result.length, 3);
- result = a.query({
- colors: {
- $any: ["yellow", "blue"]
- }
- });
- return equal(result.length, 2);
- });
-
- test("$size operator", function() {
- var a, result;
- a = create();
- result = a.query({
- colors: {
- $size: 3
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Home");
- });
-
- test("$exists operator", function() {
- var a, result;
- a = create();
- result = a.query({
- featured: {
- $exists: true
- }
- });
- return equal(result.length, 2);
- });
-
- test("$has operator", function() {
- var a, result;
- a = create();
- result = a.query({
- featured: {
- $exists: false
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Contact");
- });
-
- test("$like operator", function() {
- var a, result;
- a = create();
- result = a.query({
- content: {
- $like: "javascript"
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("$like operator 2", function() {
- var a, result;
- a = create();
- result = a.query({
- content: {
- $like: "content"
- }
- });
- return equal(result.length, 3);
- });
-
- test("$likeI operator", function() {
- var a, result;
- a = create();
- result = a.query({
- content: {
- $likeI: "dummy"
- }
- });
- equal(result.length, 3);
- result = a.query({
- content: {
- $like: "dummy"
- }
- });
- return equal(result.length, 1);
- });
-
- test("$regex", function() {
- var a, result;
- a = create();
- result = a.query({
- content: {
- $regex: /javascript/gi
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("$regex2", function() {
- var a, result;
- a = create();
- result = a.query({
- content: {
- $regex: /dummy/
- }
- });
- return equal(result.length, 1);
- });
-
- test("$regex3", function() {
- var a, result;
- a = create();
- result = a.query({
- content: {
- $regex: /dummy/i
- }
- });
- return equal(result.length, 3);
- });
-
- test("$regex4", function() {
- var a, result;
- a = create();
- result = a.query({
- content: /javascript/i
- });
- return equal(result.length, 1);
- });
-
- test("$cb - callback", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $cb: function(attr) {
- return attr.charAt(0).toLowerCase() === "c";
- }
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Contact");
- });
-
- test("$cb - callback - checking 'this' is the model", function() {
- var a, result;
- a = create();
- result = a.query({
- title: {
- $cb: function(attr) {
- return this.get("title") === "Home";
- }
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Home");
- });
-
- test("$and operator", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 5
- },
- colors: {
- $contains: "yellow"
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Home");
- });
-
- test("$and operator (explicit)", function() {
- var a, result;
- a = create();
- result = a.query({
- $and: {
- likes: {
- $gt: 5
- },
- colors: {
- $contains: "yellow"
- }
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "Home");
- });
-
- test("$or operator", function() {
- var a, result;
- a = create();
- result = a.query({
- $or: {
- likes: {
- $gt: 5
- },
- colors: {
- $contains: "yellow"
- }
- }
- });
- return equal(result.length, 2);
- });
-
- test("$nor operator", function() {
- var a, result;
- a = create();
- result = a.query({
- $nor: {
- likes: {
- $gt: 5
- },
- colors: {
- $contains: "yellow"
- }
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("Compound Queries", function() {
- var a, result;
- a = create();
- result = a.query({
- $and: {
- likes: {
- $gt: 5
- }
- },
- $or: {
- content: {
- $like: "PHP"
- },
- colors: {
- $contains: "yellow"
- }
- }
- });
- equal(result.length, 2);
- result = a.query({
- $and: {
- likes: {
- $lt: 15
- }
- },
- $or: {
- content: {
- $like: "Dummy"
- },
- featured: {
- $exists: true
- }
- },
- $not: {
- colors: {
- $contains: "yellow"
- }
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("title"), "About");
- });
-
- test("Limit", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- limit: 2
- });
- return equal(result.length, 2);
- });
-
- test("Offset", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- limit: 2,
- offset: 2
- });
- return equal(result.length, 1);
- });
-
- test("Page", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- limit: 3,
- page: 2
- });
- return equal(result.length, 0);
- });
-
- test("Sorder by model key", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- sortBy: "likes"
- });
- equal(result.length, 3);
- equal(result[0].get("title"), "About");
- equal(result[1].get("title"), "Home");
- return equal(result[2].get("title"), "Contact");
- });
-
- test("Sorder by model key with descending order", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- sortBy: "likes",
- order: "desc"
- });
- equal(result.length, 3);
- equal(result[2].get("title"), "About");
- equal(result[1].get("title"), "Home");
- return equal(result[0].get("title"), "Contact");
- });
-
- test("Sorder by function", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(result.length, 3);
- equal(result[2].get("title"), "About");
- equal(result[0].get("title"), "Home");
- return equal(result[1].get("title"), "Contact");
- });
-
- test("cache", function() {
- var a, result;
- a = create();
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(result.length, 3);
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(result.length, 3);
- a.remove(result[0]);
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(result.length, 2);
- result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- return equal(result.length, 3);
- });
-
- test("cache with multiple collections", function() {
- var a, a_result, b, b_result;
- a = create();
- b = create();
- b.remove(b.at(0));
- equal(b.length, 2);
- equal(a.length, 3);
- a_result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(a_result.length, 3);
- b_result = b.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(b_result.length, 2);
- a.remove(a_result[0]);
- b.remove(b_result[0]);
- a_result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(a_result.length, 3);
- equal(a.length, 2);
- b_result = b.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(b_result.length, 2);
- equal(b.length, 1);
- a.reset_query_cache();
- a_result = a.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(a_result.length, 2);
- equal(a.length, 2);
- b_result = b.query({
- likes: {
- $gt: 1
- }
- }, {
- cache: true,
- sortBy: function(model) {
- return model.get("title").charAt(2);
- }
- });
- equal(b_result.length, 2);
- return equal(b.length, 1);
- });
-
- test("null attribute with various operators", function() {
- var a, result;
- a = create();
- result = a.query({
- wrong_key: {
- $like: "test"
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $regex: /test/
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $contains: "test"
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $all: [12, 23]
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $any: [12, 23]
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $size: 10
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $in: [12, 23]
- }
- });
- equal(result.length, 0);
- result = a.query({
- wrong_key: {
- $nin: [12, 23]
- }
- });
- return equal(result.length, 0);
- });
-
- test("Where method", function() {
- var a, result;
- a = create();
- result = a.where({
- likes: {
- $gt: 5
- }
- });
- equal(result.length, 2);
- return equal(result.models.length, result.length);
- });
-
- test("$computed", function() {
- var a, b, c, result, testModel;
- testModel = (function(_super) {
-
- __extends(testModel, _super);
-
- testModel.name = 'testModel';
-
- function testModel() {
- return testModel.__super__.constructor.apply(this, arguments);
- }
-
- testModel.prototype.full_name = function() {
- return "" + (this.get('first_name')) + " " + (this.get('last_name'));
- };
-
- return testModel;
-
- })(Backbone.Model);
- a = new testModel({
- first_name: "Dave",
- last_name: "Tonge"
- });
- b = new testModel({
- first_name: "John",
- last_name: "Smith"
- });
- c = new QueryCollection([a, b]);
- result = c.query({
- full_name: {
- $computed: "Dave Tonge"
- }
- });
- equal(result.length, 1);
- equal(result[0].get("first_name"), "Dave");
- result = c.query({
- full_name: {
- $computed: {
- $likeI: "n sm"
- }
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("first_name"), "John");
- });
-
- test("$elemMatch", function() {
- var a, b, result, text_search;
- a = new QueryCollection([
- {
- title: "Home",
- comments: [
- {
- text: "I like this post"
- }, {
- text: "I love this post"
- }, {
- text: "I hate this post"
- }
- ]
- }, {
- title: "About",
- comments: [
- {
- text: "I like this page"
- }, {
- text: "I love this page"
- }, {
- text: "I really like this page"
- }
- ]
- }
- ]);
- b = new QueryCollection([
- {
- foo: [
- {
- shape: "square",
- color: "purple",
- thick: false
- }, {
- shape: "circle",
- color: "red",
- thick: true
- }
- ]
- }, {
- foo: [
- {
- shape: "square",
- color: "red",
- thick: true
- }, {
- shape: "circle",
- color: "purple",
- thick: false
- }
- ]
- }
- ]);
- text_search = {
- $likeI: "love"
- };
- result = a.query({
- $or: {
- comments: {
- $elemMatch: {
- text: text_search
- }
- },
- title: text_search
- }
- });
- equal(result.length, 2);
- result = a.query({
- $or: {
- comments: {
- $elemMatch: {
- text: /post/
- }
- }
- }
- });
- equal(result.length, 1);
- result = a.query({
- $or: {
- comments: {
- $elemMatch: {
- text: /post/
- }
- },
- title: /about/i
- }
- });
- equal(result.length, 2);
- result = a.query({
- $or: {
- comments: {
- $elemMatch: {
- text: /really/
- }
- }
- }
- });
- equal(result.length, 1);
- result = b.query({
- foo: {
- $elemMatch: {
- shape: "square",
- color: "purple"
- }
- }
- });
- return equal(result.length, 1);
- });
-
- test("$any and $all", function() {
- var a, b, c, d, e, result;
- a = {
- name: "test",
- tags1: ["red", "yellow"],
- tags2: ["orange", "green", "red", "blue"]
- };
- b = {
- name: "test1",
- tags1: ["purple", "blue"],
- tags2: ["orange", "red", "blue"]
- };
- c = {
- name: "test2",
- tags1: ["black", "yellow"],
- tags2: ["green", "orange", "blue"]
- };
- d = {
- name: "test3",
- tags1: ["red", "yellow", "blue"],
- tags2: ["green"]
- };
- e = new QueryCollection([a, b, c, d]);
- result = e.query({
- tags1: {
- $any: ["red", "purple"]
- },
- tags2: {
- $all: ["orange", "green"]
- }
- });
- equal(result.length, 1);
- return equal(result[0].get("name"), "test");
- });
-
-}).call(this);
View
471 test/bq-test.coffee
@@ -0,0 +1,471 @@
+# Requires
+assert = require('assert')
+{QueryCollection} = require "../src/backbone-query"
+Backbone = require('backbone')
+
+QueryCollection::findAll = QueryCollection::where_by
+
+create = ->
+ new QueryCollection [
+ {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:"Contact", colors:["red","blue"], likes:20, content: "Dummy content about PHP"}
+ ]
+
+
+describe "Backbone Query Tests", ->
+
+ it "Equals query", ->
+ a = create()
+ result = a.query title:"Home"
+ assert.equal result.length, 1
+ assert.equal result[0].get("title"), "Home"
+
+ #result = a.findAll colors: "blue"
+ #assert.equal result.length, 2
+
+ #result = a.findAll colors: ["red", "blue"]
+ #assert.equal result.length, 1
+
+
+
+ it "Simple equals query (no results)", ->
+ a = create()
+ result = a.findAll title:"Homes"
+ assert.equal result.length, 0
+
+ it "Simple equals query with explicit $equal", ->
+ a = create()
+ result = a.findAll title: {$equal: "About"}
+ assert.equal result.length, 1
+ assert.equal result.at(0).get("title"), "About"
+
+ it "$contains operator", ->
+ a = create()
+ result = a.findAll colors: {$contains: "blue"}
+ assert.equal result.length, 2
+
+ it "$ne operator", ->
+ a = create()
+ result = a.findAll title: {$ne: "Home"}
+ assert.equal result.length, 2
+
+ it "$lt operator", ->