UNPKG

nodebook-nbql

Version:

Filter query language for nodebook

437 lines (378 loc) 15.6 kB
/* globals describe, it */ /* jshint unused:false */ var should = require('should'), nbql = require('../lib/nbql'); describe('Parser', function () { var parserError = /^Query Error: unexpected character in filter at char/; describe('Operators', function () { it('can parse standard equals', function () { nbql.parse('count:5').should.eql({ statements: [ {prop: 'count', op: '=', value: 5} ] }); nbql.parse('tag:getting-started').should.eql({ statements: [ {prop: 'tag', op: '=', value: 'getting-started'} ] }); nbql.parse('author:\'Joe Bloggs\'').should.eql({ statements: [ {prop: 'author', op: '=', value: 'Joe Bloggs'} ] }); nbql.parse('author:123-test').should.eql({ statements: [ {prop: 'author', op: '=', value: '123-test'} ] }); }); it('can parse not equals', function () { nbql.parse('count:-5').should.eql({ statements: [ {prop: 'count', op: '!=', value: 5} ] }); nbql.parse('tag:-getting-started').should.eql({ statements: [ {prop: 'tag', op: '!=', value: 'getting-started'} ] }); nbql.parse('author:-\'Joe Bloggs\'').should.eql({ statements: [ {prop: 'author', op: '!=', value: 'Joe Bloggs'} ] }); }); it('can parse greater than', function () { nbql.parse('count:>5').should.eql({ statements: [ {prop: 'count', op: '>', value: 5} ] }); nbql.parse('tag:>getting-started').should.eql({ statements: [ {prop: 'tag', op: '>', value: 'getting-started'} ] }); nbql.parse('author:>\'Joe Bloggs\'').should.eql({ statements: [ {prop: 'author', op: '>', value: 'Joe Bloggs'} ] }); }); it('can parse less than', function () { nbql.parse('count:<5').should.eql({ statements: [ {prop: 'count', op: '<', value: 5} ] }); nbql.parse('tag:<getting-started').should.eql({ statements: [ {prop: 'tag', op: '<', value: 'getting-started'} ] }); nbql.parse('author:<\'Joe Bloggs\'').should.eql({ statements: [ {prop: 'author', op: '<', value: 'Joe Bloggs'} ] }); }); it('can parse greater than or equals', function () { nbql.parse('count:>=5').should.eql({ statements: [ {prop: 'count', op: '>=', value: 5} ] }); nbql.parse('tag:>=getting-started').should.eql({ statements: [ {prop: 'tag', op: '>=', value: 'getting-started'} ] }); nbql.parse('author:>=\'Joe Bloggs\'').should.eql({ statements: [ {prop: 'author', op: '>=', value: 'Joe Bloggs'} ] }); }); it('can parse less than or equals', function () { nbql.parse('count:<=5').should.eql({ statements: [ {prop: 'count', op: '<=', value: 5} ] }); nbql.parse('tag:<=getting-started').should.eql({ statements: [ {prop: 'tag', op: '<=', value: 'getting-started'} ] }); nbql.parse('author:<=\'Joe Bloggs\'').should.eql({ statements: [ {prop: 'author', op: '<=', value: 'Joe Bloggs'} ] }); }); it('can parse IN with single value', function () { nbql.parse('count:[5]').should.eql({ statements: [ {prop: 'count', op: 'IN', value: [5]} ] }); nbql.parse('tag:[getting-started]').should.eql({ statements: [ {prop: 'tag', op: 'IN', value: ['getting-started']} ] }); nbql.parse('author:[\'Joe Bloggs\']').should.eql({ statements: [ {prop: 'author', op: 'IN', value: ['Joe Bloggs']} ] }); }); it('can parse NOT IN with single value', function () { nbql.parse('count:-[5]').should.eql({ statements: [ {prop: 'count', op: 'NOT IN', value: [5]} ] }); nbql.parse('tag:-[getting-started]').should.eql({ statements: [ {prop: 'tag', op: 'NOT IN', value: ['getting-started']} ] }); nbql.parse('author:-[\'Joe Bloggs\']').should.eql({ statements: [ {prop: 'author', op: 'NOT IN', value: ['Joe Bloggs']} ] }); }); it('can parse IN with multiple values', function () { nbql.parse('count:[5, 8, 12]').should.eql({ statements: [ {prop: 'count', op: 'IN', value: [5, 8, 12]} ] }); nbql.parse('tag:[getting-started, ghost, really-long-1]').should.eql({ statements: [ {prop: 'tag', op: 'IN', value: ['getting-started', 'ghost', 'really-long-1']} ] }); nbql.parse('author:[\'Joe Bloggs\', \'John O\\\'Nolan\', \'Hello World\']').should.eql({ statements: [ {prop: 'author', op: 'IN', value: ['Joe Bloggs', 'John O\'Nolan', 'Hello World']} ] }); }); it('can parse NOT IN with single value', function () { nbql.parse('count:-[5, 8, 12]').should.eql({ statements: [ {prop: 'count', op: 'NOT IN', value: [5, 8, 12]} ] }); nbql.parse('tag:-[getting-started, ghost, really-long-1]').should.eql({ statements: [ {prop: 'tag', op: 'NOT IN', value: ['getting-started', 'ghost', 'really-long-1']} ] }); nbql.parse('author:-[\'Joe Bloggs\', \'John O\\\'Nolan\', \'Hello World\']').should.eql({ statements: [ {prop: 'author', op: 'NOT IN', value: ['Joe Bloggs', 'John O\'Nolan', 'Hello World']} ] }); }); }); describe('Values', function () { it('can parse null', function () { nbql.parse('image:null').should.eql({ statements: [ {prop: 'image', op: 'IS', value: null} ] }); }); it('can parse NOT null', function () { nbql.parse('image:-null').should.eql({ statements: [ {prop: 'image', op: 'IS NOT', value: null} ] }); }); it('can parse true', function () { nbql.parse('featured:true').should.eql({ statements: [ {prop: 'featured', op: '=', value: true} ] }); }); it('can parse NOT true', function () { nbql.parse('featured:-true').should.eql({ statements: [ {prop: 'featured', op: '!=', value: true} ] }); }); it('can parse false', function () { nbql.parse('featured:false').should.eql({ statements: [ {prop: 'featured', op: '=', value: false} ] }); }); it('can parse NOT false', function () { nbql.parse('featured:-false').should.eql({ statements: [ {prop: 'featured', op: '!=', value: false} ] }); }); it('can parse a Number', function () { nbql.parse('count:5').should.eql({ statements: [ {prop: 'count', op: '=', value: 5} ] }); }); it('can parse NOT a Number', function () { nbql.parse('count:-5').should.eql({ statements: [ {prop: 'count', op: '!=', value: 5} ] }); }); }); describe('simple expressions', function () { it('should parse simple id & value combos', function () { nbql.parse('id:3').should.eql({ statements: [ {prop: 'id', op: '=', value: 3} ] }); nbql.parse('slug:getting-started').should.eql({ statements: [ {prop: 'slug', op: '=', value: 'getting-started'} ] }); }); }); describe('complex examples', function () { it('many expressions', function () { nbql.parse('tag:photo+featured:true,tag.count:>5').should.eql({ statements: [ {op: '=', value: 'photo', prop: 'tag'}, {op: '=', value: true, prop: 'featured', func: 'and'}, {op: '>', value: 5, prop: 'tag.count', func: 'or'} ] }); nbql.parse('tag:photo+image:-null,tag.count:>5').should.eql({ statements: [ {op: '=', value: 'photo', prop: 'tag'}, {op: 'IS NOT', value: null, prop: 'image', func: 'and'}, {op: '>', value: 5, prop: 'tag.count', func: 'or'} ] }); }); it('grouped expressions', function () { nbql.parse('author:-joe+(tag:photo,image:-null,featured:true)').should.eql({ statements: [ {op: '!=', value: 'joe', prop: 'author'}, { group: [ {op: '=', value: 'photo', prop: 'tag'}, {op: 'IS NOT', value: null, prop: 'image', func: 'or'}, {op: '=', value: true, prop: 'featured', func: 'or'} ], func: 'and' } ] }); nbql.parse('(tag:photo,image:-null,featured:true)+author:-joe').should.eql({ statements: [ { group: [ {op: '=', value: 'photo', prop: 'tag'}, {op: 'IS NOT', value: null, prop: 'image', func: 'or'}, {op: '=', value: true, prop: 'featured', func: 'or'} ] }, {op: '!=', value: 'joe', prop: 'author', func: 'and'} ] }); nbql.parse('author:-joe,(tag:photo,image:-null,featured:true)').should.eql({ statements: [ {op: '!=', value: 'joe', prop: 'author'}, { group: [ {op: '=', value: 'photo', prop: 'tag'}, {op: 'IS NOT', value: null, prop: 'image', func: 'or'}, {op: '=', value: true, prop: 'featured', func: 'or'} ], func: 'or' } ] }); nbql.parse('(tag:photo,image:-null,featured:false),author:-joe').should.eql({ statements: [ { group: [ {op: '=', value: 'photo', prop: 'tag'}, {op: 'IS NOT', value: null, prop: 'image', func: 'or'}, {op: '=', value: false, prop: 'featured', func: 'or'} ] }, {op: '!=', value: 'joe', prop: 'author', func: 'or'} ] }); }); it('in expressions', function () { nbql.parse('author:-joe+tag:[photo,video]').should.eql({ statements: [ {op: '!=', value: 'joe', prop: 'author'}, {op: 'IN', value: ['photo', 'video'], prop: 'tag', func: 'and'} ] }); nbql.parse('author:-joe+tag:-[photo,video,audio]').should.eql({ statements: [ {op: '!=', value: 'joe', prop: 'author'}, {op: 'NOT IN', value: ['photo', 'video', 'audio'], prop: 'tag', func: 'and'} ] }); nbql.parse('author:-joe+tag:[photo,video,magic,\'audio\']+post.count:>5+post.count:<100').should.eql({ statements: [ {op: '!=', value: 'joe', prop: 'author'}, {op: 'IN', value: ['photo', 'video', 'magic', 'audio'], prop: 'tag', func: 'and'}, {op: '>', value: 5, prop: 'post.count', func: 'and'}, {op: '<', value: 100, prop: 'post.count', func: 'and'} ] }); }); }); describe('whitespace rules', function () { it('will ignore whitespace in expressions', function () { nbql.parse('count: -5').should.eql(nbql.parse('count:-5')); nbql.parse('author: -joe + tag: [photo, video]').should.eql(nbql.parse('author:-joe+tag:[photo,video]')); }); it('will not ignore whitespace in Strings', function () { nbql.parse('author:\'Hello World\'').should.not.eql(nbql.parse('author:\'HelloWorld\'')); }); }); describe('invalid expressions', function () { it('CANNOT parse characters outside of a STRING value', function () { (function () { nbql.parse('tag:\'My Tag\'-');}).should.throw(parserError); }); it('CANNOT parse property - operator - value in wrong order', function () { (function () { nbql.parse('\'My Tag\':tag');}).should.throw(parserError); (function () { nbql.parse('5>:tag');}).should.throw(parserError); }); it('CANNOT parse combination without filter expression', function () { (function () { nbql.parse('count:3+');}).should.throw(parserError); (function () { nbql.parse(',count:3');}).should.throw(parserError); }); it('CANNOT parse incomplete group', function () { (function () { nbql.parse('id:5,(count:3');}).should.throw(parserError); (function () { nbql.parse('count:3)');}).should.throw(parserError); (function () { nbql.parse('id:5(count:3)');}).should.throw(parserError); }); it('CANNOT parse invalid IN expression', function () { (function () { nbql.parse('id:[test+ing]');}).should.throw(parserError); (function () { nbql.parse('id:[test');}).should.throw(parserError); (function () { nbql.parse('id:test,ing]');}).should.throw(parserError); }); }); });