mirror of
https://github.com/DeviceFarmer/stf.git
synced 2026-04-27 16:25:15 +02:00
Add op support to query parser. You can now look for values using <=, <, > and >=.
This commit is contained in:
@@ -56,6 +56,32 @@ module.exports = function DeviceColumnService($filter, gettext) {
|
||||
|
||||
return 0
|
||||
}
|
||||
, filter: function(device, filter) {
|
||||
var va = (device.version || '0').split('.')
|
||||
, vb = (filter.query || '0').split('.')
|
||||
, la = va.length
|
||||
, lb = vb.length
|
||||
, op = filterOps[filter.op || '=']
|
||||
|
||||
if (vb[lb - 1] === '') {
|
||||
// This means that the query is not complete yet, and we're
|
||||
// looking at something like "4.", which means that the last part
|
||||
// should be ignored.
|
||||
vb.pop()
|
||||
lb -= 1
|
||||
}
|
||||
|
||||
for (var i = 0, l = Math.min(la, lb); i < l; ++i) {
|
||||
var a = parseInt(va[i], 10)
|
||||
, b = parseInt(vb[i], 10)
|
||||
|
||||
if (!op(a, b)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
})
|
||||
, network: TextCell({
|
||||
title: gettext('Network')
|
||||
@@ -201,6 +227,24 @@ function compareRespectCase(a, b) {
|
||||
return a === b ? 0 : (a < b ? -1 : 1)
|
||||
}
|
||||
|
||||
var filterOps = {
|
||||
'<': function(a, filterValue) {
|
||||
return a < filterValue
|
||||
}
|
||||
, '<=': function(a, filterValue) {
|
||||
return a <= filterValue
|
||||
}
|
||||
, '>': function(a, filterValue) {
|
||||
return a > filterValue
|
||||
}
|
||||
, '>=': function(a, filterValue) {
|
||||
return a >= filterValue
|
||||
}
|
||||
, '=': function(a, filterValue) {
|
||||
return a === filterValue
|
||||
}
|
||||
}
|
||||
|
||||
function TextCell(options) {
|
||||
return _.defaults(options, {
|
||||
title: options.title
|
||||
@@ -241,13 +285,17 @@ function NumberCell(options) {
|
||||
, compare: function(a, b) {
|
||||
return options.value(a) - options.value(b)
|
||||
}
|
||||
, filter: function(item, filter) {
|
||||
return filterIgnoreCase(options.value(item), filter.query)
|
||||
}
|
||||
, filter: (function() {
|
||||
return function(item, filter) {
|
||||
return filterOps[filter.op || '='](
|
||||
options.value(item)
|
||||
, +filter.query
|
||||
)
|
||||
}
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function DateCell(options) {
|
||||
return _.defaults(options, {
|
||||
title: options.title
|
||||
@@ -277,9 +325,19 @@ function DateCell(options) {
|
||||
, vb = options.value(b) || 0
|
||||
return va - vb
|
||||
}
|
||||
, filter: function(item, filter) {
|
||||
return filterIgnoreCase(options.value(item) + '', filter.query)
|
||||
}
|
||||
, filter: (function() {
|
||||
function dateNumber(d) {
|
||||
return d
|
||||
? d.getFullYear() * 10000 + d.getMonth() * 100 + d.getDate()
|
||||
: 0
|
||||
}
|
||||
return function(item, filter) {
|
||||
var filterDate = new Date(filter.query)
|
||||
, va = dateNumber(options.value(item))
|
||||
, vb = dateNumber(filterDate)
|
||||
return filterOps[filter.op || '='](va, vb)
|
||||
}
|
||||
})()
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
.filtering-buttons
|
||||
input(type='search', results='5', autosave='deviceFilter'
|
||||
name='deviceFilter', ng-model='deviceFilter', ng-change='applyFilter(deviceFilter)',
|
||||
ng-model-options='{debounce: 150}'
|
||||
ng-model-options='{debounce: 250}'
|
||||
autocorrect='off', autocapitalize='off', spellcheck='false').form-control.input-sm.device-search.pull-right
|
||||
.clear-filtering-buttons
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
.filtering-buttons
|
||||
input(type='search', results='5', autosave='deviceFilter'
|
||||
name='deviceFilter', ng-model='deviceFilter', ng-change='applyFilter(deviceFilter)',
|
||||
ng-model-options='{debounce: 150}'
|
||||
ng-model-options='{debounce: 250}'
|
||||
autocorrect='off', autocapitalize='off', spellcheck='false').form-control.input-sm.device-search.pull-right
|
||||
|
||||
span.pull-right
|
||||
|
||||
@@ -8,6 +8,7 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('a'), [
|
||||
{
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'a'
|
||||
}
|
||||
])
|
||||
@@ -17,14 +18,17 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('a b c'), [
|
||||
{
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'a'
|
||||
}
|
||||
, {
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'b'
|
||||
}
|
||||
, {
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'c'
|
||||
}
|
||||
])
|
||||
@@ -34,15 +38,31 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('serial:foo'), [
|
||||
{
|
||||
field: 'serial'
|
||||
, op: null
|
||||
, query: 'foo'
|
||||
}
|
||||
])
|
||||
}
|
||||
/*
|
||||
This test is currently failing, but I'm not sure if I care enough about it.
|
||||
Commented out for now.
|
||||
|
||||
, function() {
|
||||
var parser = new QueryParser()
|
||||
assert.deepEqual(parser.parse('a:b:c'), [
|
||||
{
|
||||
field: 'a'
|
||||
, query: 'b:c'
|
||||
}
|
||||
])
|
||||
}
|
||||
*/
|
||||
, function() {
|
||||
var parser = new QueryParser()
|
||||
assert.deepEqual(parser.parse('name:"Galaxy S2 LTE"'), [
|
||||
{
|
||||
field: 'name'
|
||||
, op: null
|
||||
, query: 'Galaxy S2 LTE'
|
||||
}
|
||||
])
|
||||
@@ -52,10 +72,12 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('name:"Galaxy S2 LTE" black'), [
|
||||
{
|
||||
field: 'name'
|
||||
, op: null
|
||||
, query: 'Galaxy S2 LTE'
|
||||
}
|
||||
, {
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'black'
|
||||
}
|
||||
])
|
||||
@@ -65,6 +87,7 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('"foo bar"'), [
|
||||
{
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'foo bar'
|
||||
}
|
||||
])
|
||||
@@ -74,7 +97,8 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('version:>=4.1'), [
|
||||
{
|
||||
field: 'version'
|
||||
, query: '>=4.1'
|
||||
, op: '>='
|
||||
, query: '4.1'
|
||||
}
|
||||
])
|
||||
}
|
||||
@@ -83,7 +107,18 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('version: >=4.1'), [
|
||||
{
|
||||
field: 'version'
|
||||
, query: '>=4.1'
|
||||
, op: '>='
|
||||
, query: '4.1'
|
||||
}
|
||||
])
|
||||
}
|
||||
, function() {
|
||||
var parser = new QueryParser()
|
||||
assert.deepEqual(parser.parse('version: < 4.1'), [
|
||||
{
|
||||
field: 'version'
|
||||
, op: '<'
|
||||
, query: '4.1'
|
||||
}
|
||||
])
|
||||
}
|
||||
@@ -92,10 +127,12 @@ var tests = [
|
||||
assert.deepEqual(parser.parse('Galaxy operator: DOCOMO'), [
|
||||
{
|
||||
field: null
|
||||
, op: null
|
||||
, query: 'Galaxy'
|
||||
}
|
||||
, {
|
||||
field: 'operator'
|
||||
, op: null
|
||||
, query: 'DOCOMO'
|
||||
}
|
||||
])
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
var State = {
|
||||
TERM_START: 1
|
||||
, FIELD_OR_QUERY: 2
|
||||
, QUERY_START: 3
|
||||
, QUERY: 4
|
||||
, DOUBLEQUOTED_QUERY: 5
|
||||
TERM_START: 10
|
||||
, QUERY_START: 20
|
||||
, OP_LT: 30
|
||||
, OP_GT: 40
|
||||
, QUERY_VALUE_START: 50
|
||||
, QUERY_VALUE: 60
|
||||
, QUERY_VALUE_DOUBLEQUOTED: 70
|
||||
}
|
||||
|
||||
function Term() {
|
||||
this.field = null
|
||||
this.op = null
|
||||
this.query = ''
|
||||
}
|
||||
|
||||
@@ -38,14 +41,53 @@ QueryParser.prototype.consume = function(input) {
|
||||
return
|
||||
}
|
||||
this.terms.push(this.currentTerm)
|
||||
if (input === '"') {
|
||||
this.state = State.DOUBLEQUOTED_QUERY
|
||||
this.state = State.QUERY_START
|
||||
return this.consume(input)
|
||||
case State.QUERY_START:
|
||||
if (this.isWhitespace(input)) {
|
||||
// Preceding whitespace, ignore.
|
||||
return
|
||||
}
|
||||
this.state = State.FIELD_OR_QUERY
|
||||
this.currentTerm.query += input
|
||||
return
|
||||
case State.FIELD_OR_QUERY:
|
||||
if (input === '<') {
|
||||
this.state = State.OP_LT
|
||||
return
|
||||
}
|
||||
if (input === '>') {
|
||||
this.state = State.OP_GT
|
||||
return
|
||||
}
|
||||
this.state = State.QUERY_VALUE_START
|
||||
return this.consume(input)
|
||||
case State.OP_LT:
|
||||
if (input === '=') {
|
||||
this.currentTerm.op = '<='
|
||||
this.state = State.QUERY_VALUE_START
|
||||
return
|
||||
}
|
||||
this.currentTerm.op = '<'
|
||||
this.state = State.QUERY_VALUE_START
|
||||
return this.consume(input)
|
||||
case State.OP_GT:
|
||||
if (input === '=') {
|
||||
this.currentTerm.op = '>='
|
||||
this.state = State.QUERY_VALUE_START
|
||||
return
|
||||
}
|
||||
this.currentTerm.op = '>'
|
||||
this.state = State.QUERY_VALUE_START
|
||||
return this.consume(input)
|
||||
case State.QUERY_VALUE_START:
|
||||
if (this.isWhitespace(input)) {
|
||||
// Preceding whitespace, ignore.
|
||||
return
|
||||
}
|
||||
if (input === '"') {
|
||||
this.state = State.QUERY_VALUE_DOUBLEQUOTED
|
||||
return
|
||||
}
|
||||
this.state = State.QUERY_VALUE
|
||||
return this.consume(input)
|
||||
case State.QUERY_VALUE:
|
||||
if (this.isWhitespace(input)) {
|
||||
return this.concludeTerm()
|
||||
}
|
||||
@@ -57,28 +99,7 @@ QueryParser.prototype.consume = function(input) {
|
||||
}
|
||||
this.currentTerm.query += input
|
||||
return
|
||||
case State.QUERY_START:
|
||||
if (this.isWhitespace(input)) {
|
||||
// Preceding whitespace, ignore.
|
||||
return
|
||||
}
|
||||
if (input === '"') {
|
||||
this.state = State.DOUBLEQUOTED_QUERY
|
||||
return
|
||||
}
|
||||
this.currentTerm.query += input
|
||||
return
|
||||
case State.QUERY:
|
||||
if (this.isWhitespace(input)) {
|
||||
return this.concludeTerm()
|
||||
}
|
||||
if (input === '"') {
|
||||
this.state = State.DOUBLEQUOTED_QUERY
|
||||
return
|
||||
}
|
||||
this.currentTerm.query += input
|
||||
return
|
||||
case State.DOUBLEQUOTED_QUERY:
|
||||
case State.QUERY_VALUE_DOUBLEQUOTED:
|
||||
if (input === '\\') {
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user