Skip to content

Commit

Permalink
v1.1.9. Sorting improvements.
Browse files Browse the repository at this point in the history
- v1.1.9 May 17, 2012
	- Added
		- `queryEngine.generatorComparator`
		- `QueryCollection::setComparator`
		- `QueryCollection::sortCollection`
	- When creating a child collection, the parent collection's comparator
will now be copied over
	- Comparators can now be arrays of comparators too
  • Loading branch information
balupton committed May 17, 2012
1 parent 327e7a3 commit 830cf8d
Show file tree
Hide file tree
Showing 10 changed files with 333 additions and 95 deletions.
11 changes: 10 additions & 1 deletion History.md
@@ -1,13 +1,22 @@
## History

- v1.1.9 May 17, 2012
- Added
- `queryEngine.generatorComparator`
- `QueryCollection::setComparator`
- `QueryCollection::sortCollection`
- When creating a child collection, the parent collection's comparator will now be copied over
- Comparators can now be arrays of comparators too

- v1.1.8 May 15, 2012
- Fixed boolean comparison
- Now uses CoffeeScripts `extends` rather than `Backbone.extend`

- v1.1.6 May 8, 2012
- Cleaned the code up a little bit
- Aliases `$beginsWith` with `$startsWith`, and `$endsWith` with `$finishesWith`
- Which all now support array values, e.g. `something: $beginsWith: ['a','b','c']`
- Exposes the uses Backbone.js module through `QueryEngine.Backbone`
- Exposes the used Backbone.js module through `queryEngine.Backbone`
- You should use this instead of including your own backbone module due to [this bug](https://github.com/documentcloud/backbone/issues/1288) in Backbone.js

- v1.1.4 and v1.1.5
Expand Down
7 changes: 5 additions & 2 deletions Makefile
@@ -1,5 +1,8 @@
test:
./node_modules/.bin/mocha
node ./node_modules/mocha/bin/mocha

test-debug:
node ./node_modules/mocha/bin/mocha --debug-brk

test-global:
mocha
Expand All @@ -10,4 +13,4 @@ compile:
dev:
./node_modules/.bin/coffee -w -c lib/query-engine.coffee

.PHONY: test test-global compile dev
.PHONY: test test-debug test-global compile dev
18 changes: 9 additions & 9 deletions demo/index.html
Expand Up @@ -93,15 +93,15 @@ <h2>Code:</h2>

# Perform a wildcard search
else if true
result = queryEngine.createLiveCollection()
.setFilter('search', (model,searchString) ->
searchRegex = queryEngine.createSafeRegex searchString
pass = searchRegex.test(model.get('title')) or searchRegex.test(model.get('content'))
return pass
)
.setSearchString('about') # try it with "this", or "the" as well :)
.add(models)
.toJSON()
result = queryEngine.createLiveCollection()
.setFilter('search', (model,searchString) ->
searchRegex = queryEngine.createSafeRegex(searchString)
pass = searchRegex.test(model.get('title')) or searchRegex.test(model.get('content'))
return pass
)
.setSearchString('about') # try it with "this", or "the" as well :)
.add(models)
.toJSON()

# Perform a pill search
else if true
Expand Down
102 changes: 77 additions & 25 deletions lib/query-engine.coffee
Expand Up @@ -39,6 +39,43 @@ util =
# Return the result
result

# Generate Comparator
generateComparator: (input) ->
# Creates a function for a comparator
generateFunction = (comparator) ->
unless comparator
throw new Error('Cannot sort without a comparator')
else if _.isFunction(comparator)
return comparator
else if _.isObject(comparator)
return (a,b) ->
comparison = 0
for own key,value of comparator
# Prepare
aValue = a.get?(key) or a[key]
bValue = b.get?(key) or b[key]
# Descending
if value is -1
comparison = bValue - aValue
# Ascending
else if value is 1
comparison = aValue - bValue
# Return early if we have something
return comparison if comparison
# Return likey 0
return comparison
else if _.isArray(comparator)
return (a,b) ->
comparison = 0
for value,key in comparator
comparison = generateFunction(value)(a,b)
return comparison if comparison
# Return likey 0
return comparison
else
throw new Error('Unknown comparator type')
# Return the generated function for our comparator
return generateFunction(input)

# Hash
# Extends the Array class with:
Expand Down Expand Up @@ -343,33 +380,39 @@ class QueryCollection extends Backbone.Collection
# ---------------------------------
# Generic API

# Set Comparator
setComparator: (comparator) ->
# Prepare comparator
comparator = util.generateComparator(comparator)

# Apply it
@comparator = comparator

# Chain
@

# Sort Collection
# Sorts our current collection by our comparator
sortCollection: (comparator) ->
# Sort our collection
if comparator
comparator = util.generateComparator(comparator)
@models.sort(comparator)
else
@models.sort()

# Chain
return @

# Sort Array
# Return the results as an array sorted by our comparator
sortArray: (comparator) ->
# Prepare
arr = @toJSON()
# Prepare comparator
comparator = util.generateComparator(comparator)

# Sort
if comparator
if comparator instanceof Function
arr.sort(comparator)
else if comparator instanceof Object
for own key,value of comparator
# Descending
if value is -1
arr.sort (a,b) ->
b[key] - a[key]
# Ascending
else if value is 1
arr.sort (a,b) ->
a[key] - b[key]
else
throw new Error('Unknown comparator type was passed to QueryCollection::sortArray')
else
if @comparator
return @sortArray(@comparator)
else
throw new Error('Cannot sort a set without a comparator')
# Generate the array and sort it
arr = @toJSON()
arr.sort(comparator)

# Return sorted array
return arr
Expand Down Expand Up @@ -398,6 +441,7 @@ class QueryCollection extends Backbone.Collection
createChildCollection: ->
collection = new QueryCollection()
.setParentCollection(@)
collection.comparator ?= @comparator if @comparator
return collection

# Create Live Child Collection
Expand Down Expand Up @@ -438,6 +482,8 @@ class QueryCollection extends Backbone.Collection
# Subscribe to change events on our existing models
if enabled
@on('change',@onChange)
# onChange will do our resort
# we do not need a onAdd for our resort, as backbone already does this
else
@off('change',@onChange)

Expand Down Expand Up @@ -499,10 +545,14 @@ class QueryCollection extends Backbone.Collection
# Fired when a model that is inside our own collection changes
# We should check if it still passes our tests
# and if it doesn't then we should remove the model
# We should perform a resort
onChange: (model) ->
pass = @test(model)
unless pass
@safeRemove(model)
#else
# @sortCollection()
# ^ not yet supported
@

# Fired when a model in our parent collection changes
Expand Down Expand Up @@ -820,8 +870,9 @@ class Query
match = true

# The $size operator matches any array with the specified number of elements. The following example would match the object {a:["foo"]}, since that array has just one element:
if selector.$size
if value.length? and value.length is selector.$size
$size = selector.$size or selector.$length
if $size
if value.length? and value.length is $size
match = true

# The $type operator matches values based on their BSON type.
Expand Down Expand Up @@ -889,6 +940,7 @@ exports = {
safeRegex: util.safeRegex
createRegex: util.createRegex
createSafeRegex: util.createSafeRegex
generateComparator: util.generateComparator
toArray: util.toArray
Backbone: Backbone
Hash: Hash
Expand Down
104 changes: 74 additions & 30 deletions lib/query-engine.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "query-engine",
"version": "1.1.8",
"version": "1.1.9",
"description": "Query-Engine is a NoSQL and MongoDb compliant query engine. It can run on the server-side with Node.js, or on the client-side within web browsers",
"homepage": "https://github.com/bevry/query-engine",
"keywords": [
Expand Down
2 changes: 1 addition & 1 deletion test/live.coffee
@@ -1,5 +1,5 @@
# Requires
queryEngine = require(__dirname+'/../lib/query-engine.coffee')
queryEngine = require(__dirname+'/../lib/query-engine.js')
assert = require('assert')
Backbone = require('backbone')

Expand Down
1 change: 0 additions & 1 deletion test/mocha.opts
Expand Up @@ -2,5 +2,4 @@
--ui bdd
--ignore-leaks
--growl
--bail
--compilers coffee:coffee-script

0 comments on commit 830cf8d

Please sign in to comment.