Comparing version 0.0.3 to 0.0.4
@@ -1,2 +0,2 @@ | ||
/* parser generated by jison 0.4.15 */ | ||
/* parser generated by jison 0.4.16 */ | ||
/* | ||
@@ -169,3 +169,9 @@ Returns a Parser object of the following structure: | ||
} else { | ||
throw new Error(str); | ||
function _parseError (msg, hash) { | ||
this.message = msg; | ||
this.hash = hash; | ||
} | ||
_parseError.prototype = new Error(); | ||
throw new _parseError(str, hash); | ||
} | ||
@@ -203,3 +209,3 @@ }, | ||
_token_stack: | ||
function lex() { | ||
var lex = function () { | ||
var token; | ||
@@ -211,3 +217,3 @@ token = lexer.lex() || EOF; | ||
return token; | ||
} | ||
}; | ||
var symbol, preErrorSymbol, state, action, a, r, yyval = {}, p, len, newState, expected; | ||
@@ -318,2 +324,8 @@ while (true) { | ||
// console.log("parser object definition: ", this); | ||
parser.parseError = function(errStr, object) { | ||
var lines = errStr.split("\n"); | ||
lines[0] = "Query Error: unexpected character in filter at char " + (object.loc.first_column + 1); | ||
throw new Error(lines.join("\n")); | ||
}; | ||
/* generated by jison-lex 0.3.4 */ | ||
@@ -690,2 +702,13 @@ var lexer = (function(){ | ||
}); | ||
lexer.parseError = function(errStr, object) { | ||
var lines = errStr.split("\n"), | ||
caretPos, | ||
char; | ||
caretPos = lines[2].indexOf("^"); | ||
char = lines[1].charAt(caretPos); | ||
lines[0] = "Query Error: unrecognized text \"" + char + "\" in filter at char " + (caretPos + 1); | ||
throw Error(lines.join("\n")); | ||
}; | ||
return lexer; | ||
@@ -692,0 +715,0 @@ })(); |
@@ -26,2 +26,2 @@ /** | ||
module.exports = resourceContext; | ||
module.exports = resourceContext; |
var parser = require('../dist/parser').parser; | ||
parser.yy = require("./scope"); | ||
parser.yy = require('./scope'); | ||
var lex = exports.lex = function (input) { | ||
exports.lex = function (input) { | ||
parser.lexer.setInput(input); | ||
@@ -18,4 +18,4 @@ var lexed = parser.lexer.lex(), | ||
// returns the JSON object | ||
var parse = exports.parse = function (input, resource_type, aliases) { | ||
return parser.parse(input, resource_type, aliases); | ||
exports.parse = function (input, resourceType, aliases) { | ||
return parser.parse(input, resourceType, aliases); | ||
}; | ||
@@ -22,0 +22,0 @@ |
@@ -59,5 +59,5 @@ /** | ||
addJoin(parts[0]); | ||
//if (context.relations && context.relations.indexOf(parts[parts.length - 1]) > -1) { | ||
// addJoin(path); | ||
//} | ||
// if (context.relations && context.relations.indexOf(parts[parts.length - 1]) > -1) { | ||
// addJoin(path); | ||
// } | ||
} | ||
@@ -80,4 +80,4 @@ | ||
* Detect Where Type | ||
* @param statement | ||
* @param index | ||
* @param {Object} statement | ||
* @param {int} index | ||
* @returns {string} | ||
@@ -89,3 +89,2 @@ */ | ||
whereFunc = 'where'; | ||
} else if (statement.func === 'or') { | ||
@@ -109,4 +108,4 @@ whereFunc = 'orWhere'; | ||
* | ||
* @param qb | ||
* @param statements | ||
* @param {Object} qb | ||
* @param {Array} statements | ||
* @returns {*} | ||
@@ -134,4 +133,4 @@ */ | ||
* | ||
* @param qb | ||
* @param filter | ||
* @param {Object} qb | ||
* @param {Array} filter | ||
* @returns {object} queryBuilder | ||
@@ -147,2 +146,2 @@ */ | ||
// For testing only | ||
module.exports._buildWhere = buildWhere; | ||
module.exports._buildWhere = buildWhere; |
@@ -9,3 +9,2 @@ /** | ||
var _ = require('lodash'), | ||
matchStatement, | ||
@@ -39,3 +38,3 @@ eachStatement, | ||
} | ||
}) | ||
}); | ||
}; | ||
@@ -53,3 +52,3 @@ | ||
* @param {Function} [groupFunc] - optionally provide a function to call for groups instead of automatic recursion | ||
*/ | ||
*/ | ||
eachStatement = function eachStatement(statements, func, groupFunc) { | ||
@@ -126,4 +125,4 @@ _.each(statements, function (statement, index) { | ||
if (result && index === 0 && statements[index+1] && statements[index+1].func) { | ||
delete statements[index+1].func; | ||
if (result && index === 0 && statements[index + 1] && statements[index + 1].func) { | ||
delete statements[index + 1].func; | ||
} | ||
@@ -194,3 +193,3 @@ return result; | ||
function print(indent /* strs */) { | ||
var strs = [_.fill(Array(indent), ' ').join('')].concat(Array.prototype.slice.call(arguments, 1)); | ||
var strs = [_.fill(new Array(indent), ' ').join('')].concat(Array.prototype.slice.call(arguments, 1)); | ||
console.log.apply(this, strs); | ||
@@ -213,2 +212,2 @@ } | ||
printStatements: printStatements | ||
}; | ||
}; |
var scope = {}; | ||
scope.resolveOp = function(op, value) { | ||
scope.resolveOp = function (op, value) { | ||
if (value === null) { | ||
@@ -10,3 +10,3 @@ return op === '!=' ? 'IS NOT' : 'IS'; | ||
scope.unescape = function(value) { | ||
scope.unescape = function (value) { | ||
var re = new RegExp('\\\\([\'"])', 'g'); | ||
@@ -16,3 +16,2 @@ return value.replace(re, '$1'); | ||
module.exports = scope; | ||
module.exports = scope; |
{ | ||
"name": "ghost-gql", | ||
"version": "0.0.3", | ||
"version": "0.0.4", | ||
"description": "Filter query language for Ghost", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "mocha", | ||
"build": "grunt build" | ||
"lint": "jshint lib/*.js test/*.js && jscs lib/*.js test/*.js", | ||
"test": "npm run build && npm run lint && mocha", | ||
"build": "jison src/gql.y src/gql.l -o dist/parser.js", | ||
"coverage": "istanbul cover -x src --dir=test/coverage --report=lcov ./node_modules/mocha/bin/_mocha -- test/*_spec.js", | ||
"release": "npm-release patch" | ||
}, | ||
@@ -26,8 +29,9 @@ "author": "Ghost Foundation", | ||
"devDependencies": { | ||
"grunt": "0.4.5", | ||
"grunt-mocha-istanbul": "2.4.0", | ||
"grunt-shell": "1.1.2", | ||
"jison": "0.4.15", | ||
"istanbul": "0.4.0", | ||
"jison": "0.4.16", | ||
"jscs": "2.8.0", | ||
"jshint": "2.8.0", | ||
"knex": "0.8.6", | ||
"mocha": "2.2.5", | ||
"npm-release": "1.0.0", | ||
"should": "7.0.1", | ||
@@ -34,0 +38,0 @@ "sinon": "1.15.4" |
122
README.md
# GQL | ||
GQL is a filter query language for working with Ghost's JSON API | ||
GQL stands for 'Ghost Query Language' | ||
It allows for parsing filter strings of the form `featured:true+tags.count:>10`, `tags:photo,tags:video`, etc | ||
The aim is to provide a simple gmail or github filter-like syntax for specifying conditions, whilst being flexible and powerful enough to support the majority of 'where' expressions available in SQL. | ||
The full spec can be found in <https://github.com/TryGhost/Ghost/issues/5604> | ||
GQL itself is parsed and expanded out into a JSON object which can be used to build queries in SQL (and probably No SQL). | ||
### Example: | ||
The GQL expression `featured:true+tags.count:>10` | ||
Would be converted to the following JSON object: | ||
``` | ||
{statements: [ | ||
{prop: "featured", op: "=", value: true}, | ||
{prop: "tags.count", op: ">", value: 10, func: "and"} | ||
]} | ||
``` | ||
And via Knex, would be further converted to the following SQL: | ||
`where "featured" = true and "tags"."count" > 10` | ||
Inside of Ghost, this syntax is accepted via the `filter` parameter when browsing resources in our JSON API. | ||
## What's in the box? | ||
This repository comes in three parts: | ||
- the language parsing functionality, providing `gql.parse()` | ||
- a set of lodash-like tools for processing the JSON objects returned | ||
- some currently Ghost-specific helpers for converting the JSON objects into SQL via [knex's query builder](http://knexjs.org/) | ||
The intention is to eventually move all of the Ghost-specific code and replace it with generic query-building code for Knex and perhaps also a bookshelf plugin. It should also be possible to provide other interfaces, e.g. a direct conversion to SQL or NoSQL query formats. | ||
## Usage | ||
Knex: | ||
``` | ||
var filters = gql.parse('featured:true+tags.count:>10'); | ||
gql.knexify(knex('myTable'), filters); | ||
``` | ||
Bookshelf: | ||
``` | ||
var filters = gql.parse('featured:true+tags.count:>10'); | ||
myBookshelfModel.forge().query(function (qb) { | ||
gql.knexify(qb, filters); | ||
}); | ||
``` | ||
To get raw SQL via Knex: | ||
``` | ||
var filters = gql.parse('featured:true+tags.count:>10'); | ||
var myTable = knex('myTable'); | ||
gql.knexify(myTable, filters); | ||
return myTable.toQuery(); | ||
``` | ||
### Statement processing | ||
GQL also supported grouped statements, e.g. `author:joe+(tag:photo,image:-null)` | ||
Which result in nested statements like this: | ||
``` | ||
{statements: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "IS NOT", value: null, prop: "image", func: "or"} | ||
], func: "and"} | ||
]} | ||
``` | ||
And which should result in the following SQL: | ||
`where "author"."slug" != "joe" and ("posts"."featured" = true or "posts"."image" is not null);` | ||
As the JSON returned by GQL is not always a simple set of objects, performing an operation on every statement requires a recursive loop. GQL provides tools for this: | ||
* eachStatement | ||
* findStatement | ||
* matchStatement | ||
* mergeStatements | ||
* rejectStatements | ||
* printStatements | ||
There are currently two ways that you 'could' use these functions externally (e.g. in Ghost) and in the vein of naming things is hard, I can't decide which I prefer. | ||
You could do: | ||
``` | ||
var _ = require('lodash'); | ||
_.mixin(require('ghost-gql').json); | ||
_.eachStatement(statements...); | ||
``` | ||
Or you could do | ||
``` | ||
var gql = require('ghost-gql'); | ||
gql.json.eachStatement(statements...); | ||
``` | ||
For now you'll need to use the [inline docs](https://github.com/TryGhost/GQL/blob/master/lib/lodash-stmt.js#L10) which explain how to use each function. | ||
## Syntax | ||
The full spec can be found in <https://github.com/TryGhost/Ghost/issues/5604> - I will move this eventually. | ||
## How and why | ||
GQL exists because we needed a very simple filter syntax that could be passed as a string in either a method call, a URL, or a handlebars helper attribute. The concept was originally proposed in https://github.com/TryGhost/Ghost/issues/5463#user-content-advancedfiltering and then later spec'd more fully in https://github.com/TryGhost/Ghost/issues/5604. The syntax created works well no matter whether the API is being called internally or externally. | ||
The two-step conversion process from GQL -> JSON -> SQL exists for flexibility. This library can and will handle the whole process, but with the JSON step in the middle and the lodash style tools for processing the JSON, it is possible to perform various operations on the JSON, for example, filtering out unsafe conditions. | ||
Also it's possible to implement conversion from the JSON format to SQL either via knex or without it, as well as to no-SQL JSON-like query formats. | ||
The conversion from GQL -> JSON is performed via a [JISON](http://zaach.github.io/jison/) parser. [JISON](http://zaach.github.io/jison/) is an amazing tool that allows you to easily specify the rules for a language in a JavaScript like syntax, and it creates the parser for you. | ||
In the `/src/` folder is a .l and a .y file used by JISON to generate the parser. `gql.l` is the lexer or tokenizer that defines all of the symbols that GQL can understand. `gql.y` is the grammar, it defines the rules about in what order the symbols must appear. If you make changes to `gql.l` or `gql.y`, you'll need to run `grunt build` in order to generate a new version of the parser in `/dist/`. | ||
@@ -1,6 +0,7 @@ | ||
var should = require('should'), | ||
gql = require('../lib/gql'), | ||
knex = require('knex')({}); | ||
/* globals describe, it */ | ||
var gql = require('../lib/gql'), | ||
knex = require('knex')({}), | ||
toSQL; | ||
var toSQL = exports.toSQL = function (input, resource) { | ||
toSQL = exports.toSQL = function (input, resource) { | ||
var parsedFilter = gql.parse(input); | ||
@@ -12,9 +13,9 @@ return gql.knexify(knex(resource), parsedFilter).toQuery(); | ||
it('should correctly get from GQL -> SQL', function () { | ||
toSQL("id:1", 'posts').should.eql('select * from "posts" where "posts"."id" = 1'); | ||
toSQL('id:1', 'posts').should.eql('select * from "posts" where "posts"."id" = 1'); | ||
}); | ||
it('should correctly escape bad sequences', function () { | ||
(function () {toSQL("id:'1 and 1‘=\'1`'", 'posts')}).should.throw(); | ||
toSQL("id:'1 and 1‘=\\\'1`'", 'posts').should.eql('select * from "posts" where "posts"."id" = \'1 and 1‘=\\\'1`\''); | ||
(function () {toSQL('id:\'1 and 1‘=\'1`\'', 'posts');}).should.throw(); | ||
toSQL('id:\'1 and 1‘=\\\'1`\'', 'posts').should.eql('select * from "posts" where "posts"."id" = \'1 and 1‘=\\\'1`\''); | ||
}); | ||
}); |
@@ -1,3 +0,3 @@ | ||
var should = require('should'), | ||
sinon = require('sinon'), | ||
/* globals describe, beforeEach, afterEach, it */ | ||
var sinon = require('sinon'), | ||
knex = require('knex')({}), | ||
@@ -263,8 +263,8 @@ knexify = require('../lib/knexify'); | ||
statements: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{ | ||
group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and" | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and' | ||
} | ||
@@ -300,8 +300,8 @@ ] | ||
statements: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{ | ||
group: [ | ||
{op: "=", value: "true", prop: "featured"}, | ||
{op: '=', value: 'true', prop: 'featured'}, | ||
{prop: 'image', op: 'IS NOT', value: null, func: 'or'} | ||
], func: "and" | ||
], func: 'and' | ||
} | ||
@@ -308,0 +308,0 @@ ] |
@@ -1,52 +0,52 @@ | ||
var should = require('should'), | ||
gql = require('../lib/gql'); | ||
/* globals describe, it */ | ||
var gql = require('../lib/gql'); | ||
describe('Lexer', function () { | ||
var lexicalError = /^Lexical error on line 1\. Unrecognized text\./; | ||
var lexicalError = /^Query Error: unrecognized text/; | ||
describe('Symbols', function () { | ||
it('can recognise -', function () { | ||
gql.lex("-").should.eql([{token: "NOT", matched: "-"}]); | ||
gql.lex('-').should.eql([{token: 'NOT', matched: '-'}]); | ||
}); | ||
it('can recognise +', function () { | ||
gql.lex("+").should.eql([{token: "AND", matched: "+"}]); | ||
gql.lex('+').should.eql([{token: 'AND', matched: '+'}]); | ||
}); | ||
it('can recognise ,', function () { | ||
gql.lex(",").should.eql([{token: "OR", matched: ","}]); | ||
gql.lex(',').should.eql([{token: 'OR', matched: ','}]); | ||
}); | ||
it('can recognise [', function () { | ||
gql.lex("[").should.eql([{token: "LBRACKET", matched: "["}]); | ||
gql.lex('[').should.eql([{token: 'LBRACKET', matched: '['}]); | ||
}); | ||
it('can recognise ]', function () { | ||
gql.lex("]").should.eql([{token: "RBRACKET", matched: "]"}]); | ||
gql.lex(']').should.eql([{token: 'RBRACKET', matched: ']'}]); | ||
}); | ||
it('can recognise (', function () { | ||
gql.lex("(").should.eql([{token: "LPAREN", matched: "("}]); | ||
gql.lex('(').should.eql([{token: 'LPAREN', matched: '('}]); | ||
}); | ||
it('can recognise )', function () { | ||
gql.lex(")").should.eql([{token: "RPAREN", matched: ")"}]); | ||
gql.lex(')').should.eql([{token: 'RPAREN', matched: ')'}]); | ||
}); | ||
it('can recognise >', function () { | ||
gql.lex(">").should.eql([{token: "GT", matched: ">"}]); | ||
gql.lex('>').should.eql([{token: 'GT', matched: '>'}]); | ||
}); | ||
it('can recognise <', function () { | ||
gql.lex("<").should.eql([{token: "LT", matched: "<"}]); | ||
gql.lex('<').should.eql([{token: 'LT', matched: '<'}]); | ||
}); | ||
it('can recognise >=', function () { | ||
gql.lex(">=").should.eql([{token: "GTE", matched: ">="}]); | ||
gql.lex('>=').should.eql([{token: 'GTE', matched: '>='}]); | ||
}); | ||
it('can recognise <=', function () { | ||
gql.lex("<=").should.eql([{token: "LTE", matched: "<="}]); | ||
gql.lex('<=').should.eql([{token: 'LTE', matched: '<='}]); | ||
}); | ||
it('cannot recognise :', function () { | ||
(function () {gql.lex(":")}).should.throw(lexicalError); | ||
(function () {gql.lex(':');}).should.throw(lexicalError); | ||
}); | ||
it('cannot recognise =', function () { | ||
(function () {gql.lex("=")}).should.throw(lexicalError); | ||
(function () {gql.lex('=');}).should.throw(lexicalError); | ||
}); | ||
it('cannot recognise "', function () { | ||
(function () {gql.lex('"')}).should.throw(lexicalError); | ||
(function () {gql.lex('"');}).should.throw(lexicalError); | ||
}); | ||
it('cannot recognise \'', function () { | ||
(function () {gql.lex("'")}).should.throw(lexicalError); | ||
(function () {gql.lex('\'');}).should.throw(lexicalError); | ||
}); | ||
@@ -57,37 +57,37 @@ }); | ||
it('can recognise null', function () { | ||
gql.lex("null").should.eql([{token: "NULL", matched: "null"}]); | ||
gql.lex('null').should.eql([{token: 'NULL', matched: 'null'}]); | ||
}); | ||
it('can recognise true', function () { | ||
gql.lex("true").should.eql([{token: "TRUE", matched: "true"}]); | ||
gql.lex('true').should.eql([{token: 'TRUE', matched: 'true'}]); | ||
}); | ||
it('can recognise false', function () { | ||
gql.lex("false").should.eql([{token: "FALSE", matched: "false"}]); | ||
gql.lex('false').should.eql([{token: 'FALSE', matched: 'false'}]); | ||
}); | ||
it('can recognise a LITERAL', function () { | ||
gql.lex("six").should.eql([{token: "LITERAL", matched: "six"}]); | ||
gql.lex('six').should.eql([{token: 'LITERAL', matched: 'six'}]); | ||
}); | ||
it('can recognise a STRING', function () { | ||
gql.lex("'six'").should.eql([{token: "STRING", matched: "'six'"}]); | ||
gql.lex('\'six\'').should.eql([{token: 'STRING', matched: '\'six\''}]); | ||
}); | ||
it('can recognise a NUMBER', function () { | ||
gql.lex("6").should.eql([{token: "NUMBER", matched: "6"}]); | ||
gql.lex('6').should.eql([{token: 'NUMBER', matched: '6'}]); | ||
}); | ||
it('does not confuse values in LITERALs', function () { | ||
gql.lex("strueth").should.eql([{token: "LITERAL", matched: "strueth"}]); | ||
gql.lex("trueth").should.eql([{token: "LITERAL", matched: "trueth"}]); | ||
gql.lex("true_thing").should.eql([{token: "LITERAL", matched: "true_thing"}]); | ||
//gql.lex("true-thing").should.eql([{token: "LITERAL", matched: "true-thing"}]); | ||
gql.lex('strueth').should.eql([{token: 'LITERAL', matched: 'strueth'}]); | ||
gql.lex('trueth').should.eql([{token: 'LITERAL', matched: 'trueth'}]); | ||
gql.lex('true_thing').should.eql([{token: 'LITERAL', matched: 'true_thing'}]); | ||
// gql.lex("true-thing").should.eql([{token: "LITERAL", matched: "true-thing"}]); | ||
}); | ||
it('does not confuse values in STRINGs', function () { | ||
gql.lex("'strueth'").should.eql([{token: "STRING", matched: "'strueth'"}]); | ||
gql.lex("'trueth'").should.eql([{token: "STRING", matched: "'trueth'"}]); | ||
gql.lex("'true_thing'").should.eql([{token: "STRING", matched: "'true_thing'"}]); | ||
gql.lex("'true-thing'").should.eql([{token: "STRING", matched: "'true-thing'"}]); | ||
gql.lex('\'strueth\'').should.eql([{token: 'STRING', matched: '\'strueth\''}]); | ||
gql.lex('\'trueth\'').should.eql([{token: 'STRING', matched: '\'trueth\''}]); | ||
gql.lex('\'true_thing\'').should.eql([{token: 'STRING', matched: '\'true_thing\''}]); | ||
gql.lex('\'true-thing\'').should.eql([{token: 'STRING', matched: '\'true-thing\''}]); | ||
}); | ||
@@ -98,30 +98,30 @@ }); | ||
it('should match literals', function () { | ||
gql.lex("myvalue").should.eql([ | ||
{token: "LITERAL", matched: "myvalue"} | ||
gql.lex('myvalue').should.eql([ | ||
{token: 'LITERAL', matched: 'myvalue'} | ||
]); | ||
gql.lex("my value").should.eql([ | ||
{token: "LITERAL", matched: "my"}, | ||
{token: "LITERAL", matched: "value"} | ||
gql.lex('my value').should.eql([ | ||
{token: 'LITERAL', matched: 'my'}, | ||
{token: 'LITERAL', matched: 'value'} | ||
]); | ||
gql.lex("my-value").should.eql([ | ||
{token: "LITERAL", matched: "my-value"} | ||
gql.lex('my-value').should.eql([ | ||
{token: 'LITERAL', matched: 'my-value'} | ||
]); | ||
gql.lex("my&value!").should.eql([ | ||
{token: "LITERAL", matched: "my&value!"} | ||
gql.lex('my&value!').should.eql([ | ||
{token: 'LITERAL', matched: 'my&value!'} | ||
]); | ||
gql.lex("my&valu\\'e!").should.eql([ | ||
{token: "LITERAL", matched: "my&valu\\'e!"} | ||
gql.lex('my&valu\\\'e!').should.eql([ | ||
{token: 'LITERAL', matched: 'my&valu\\\'e!'} | ||
]); | ||
(function() {gql.lex("my&valu'e!")}).should.throw(lexicalError); | ||
(function () {gql.lex('my&valu\'e!');}).should.throw(lexicalError); | ||
}); | ||
it('should separate NOT at beginning of literal', function () { | ||
gql.lex("-photo").should.eql([ | ||
{token: "NOT", matched: "-"}, | ||
{token: "LITERAL", matched: "photo"} | ||
gql.lex('-photo').should.eql([ | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LITERAL', matched: 'photo'} | ||
]); | ||
gql.lex('-photo-graph').should.eql([ | ||
{token: "NOT", matched: "-"}, | ||
{token: "LITERAL", matched: "photo-graph"} | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LITERAL', matched: 'photo-graph'} | ||
]); | ||
@@ -131,120 +131,120 @@ }); | ||
it('should NOT permit special chars inside a literal', function () { | ||
(function () { gql.lex("t+st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t,st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t(st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t)st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t>st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t<st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t=st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t[st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t]st") }).should.throw(lexicalError); | ||
(function () { gql.lex("t'st") }).should.throw(lexicalError); | ||
(function () { gql.lex('t"st') }).should.throw(lexicalError); | ||
(function () { gql.lex('t+st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t,st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t(st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t)st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t>st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t<st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t=st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t[st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t]st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t\'st');}).should.throw(lexicalError); | ||
(function () { gql.lex('t"st');}).should.throw(lexicalError); | ||
}); | ||
it('should not match special chars at the start of a literal', function () { | ||
gql.lex("+test").should.eql([ | ||
{token: "AND", matched: "+"}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('+test').should.eql([ | ||
{token: 'AND', matched: '+'}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex(",test").should.eql([ | ||
{token: "OR", matched: ","}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex(',test').should.eql([ | ||
{token: 'OR', matched: ','}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex("(test").should.eql([ | ||
{token: "LPAREN", matched: "("}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('(test').should.eql([ | ||
{token: 'LPAREN', matched: '('}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex(")test").should.eql([ | ||
{token: "RPAREN", matched: ")"}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex(')test').should.eql([ | ||
{token: 'RPAREN', matched: ')'}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex(">test").should.eql([ | ||
{token: "GT", matched: ">"}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('>test').should.eql([ | ||
{token: 'GT', matched: '>'}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex("<test").should.eql([ | ||
{token: "LT", matched: "<"}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('<test').should.eql([ | ||
{token: 'LT', matched: '<'}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex("[test").should.eql([ | ||
{token: "LBRACKET", matched: "["}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('[test').should.eql([ | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex("]test").should.eql([ | ||
{token: "RBRACKET", matched: "]"}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex(']test').should.eql([ | ||
{token: 'RBRACKET', matched: ']'}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex(">=test").should.eql([ | ||
{token: "GTE", matched: ">="}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('>=test').should.eql([ | ||
{token: 'GTE', matched: '>='}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
gql.lex("<=test").should.eql([ | ||
{token: "LTE", matched: "<="}, | ||
{token: "LITERAL", matched: "test"} | ||
gql.lex('<=test').should.eql([ | ||
{token: 'LTE', matched: '<='}, | ||
{token: 'LITERAL', matched: 'test'} | ||
]); | ||
(function () { gql.lex("=test") }).should.throw(lexicalError); | ||
(function () { gql.lex('"test') }).should.throw(lexicalError); | ||
(function () { gql.lex("'test") }).should.throw(lexicalError); | ||
(function () { gql.lex('=test');}).should.throw(lexicalError); | ||
(function () { gql.lex('"test');}).should.throw(lexicalError); | ||
(function () { gql.lex('\'test');}).should.throw(lexicalError); | ||
}); | ||
it('should not match special chars at the end of a literal', function () { | ||
gql.lex("test+").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "AND", matched: "+"} | ||
gql.lex('test+').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'AND', matched: '+'} | ||
]); | ||
gql.lex("test,").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "OR", matched: ","} | ||
gql.lex('test,').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'OR', matched: ','} | ||
]); | ||
gql.lex("test(").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "LPAREN", matched: "("} | ||
gql.lex('test(').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'LPAREN', matched: '('} | ||
]); | ||
gql.lex("test)").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "RPAREN", matched: ")"} | ||
gql.lex('test)').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'RPAREN', matched: ')'} | ||
]); | ||
gql.lex("test>").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "GT", matched: ">"} | ||
gql.lex('test>').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'GT', matched: '>'} | ||
]); | ||
gql.lex("test<").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "LT", matched: "<"} | ||
gql.lex('test<').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'LT', matched: '<'} | ||
]); | ||
gql.lex("test[").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "LBRACKET", matched: "["} | ||
gql.lex('test[').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'LBRACKET', matched: '['} | ||
]); | ||
gql.lex("test]").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "RBRACKET", matched: "]"} | ||
gql.lex('test]').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
gql.lex("test>=").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "GTE", matched: ">="} | ||
gql.lex('test>=').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'GTE', matched: '>='} | ||
]); | ||
gql.lex("test<=").should.eql([ | ||
{token: "LITERAL", matched: "test"}, | ||
{token: "LTE", matched: "<="} | ||
gql.lex('test<=').should.eql([ | ||
{token: 'LITERAL', matched: 'test'}, | ||
{token: 'LTE', matched: '<='} | ||
]); | ||
(function () { gql.lex("test=") }).should.throw(lexicalError); | ||
(function () { gql.lex('test"') }).should.throw(lexicalError); | ||
(function () { gql.lex("test'") }).should.throw(lexicalError); | ||
(function () { gql.lex('test=');}).should.throw(lexicalError); | ||
(function () { gql.lex('test"');}).should.throw(lexicalError); | ||
(function () { gql.lex('test\'');}).should.throw(lexicalError); | ||
}); | ||
it('should permit escaped special chars inside a literal', function () { | ||
gql.lex("t\\+st").should.eql([{token: "LITERAL", matched: "t\\+st"}]); | ||
gql.lex("t\\,st").should.eql([{token: "LITERAL", matched: "t\\,st"}]); | ||
gql.lex("t\\(st").should.eql([{token: "LITERAL", matched: "t\\(st"}]); | ||
gql.lex("t\\)st").should.eql([{token: "LITERAL", matched: "t\\)st"}]); | ||
gql.lex("t\\>st").should.eql([{token: "LITERAL", matched: "t\\>st"}]); | ||
gql.lex("t\\<st").should.eql([{token: "LITERAL", matched: "t\\<st"}]); | ||
gql.lex("t\\=st").should.eql([{token: "LITERAL", matched: "t\\=st"}]); | ||
gql.lex("t\\[st").should.eql([{token: "LITERAL", matched: "t\\[st"}]); | ||
gql.lex("t\\]st").should.eql([{token: "LITERAL", matched: "t\\]st"}]); | ||
gql.lex("t\\'st").should.eql([{token: "LITERAL", matched: "t\\'st"}]); | ||
gql.lex('t\\"st').should.eql([{token: "LITERAL", matched: 't\\"st'}]); | ||
gql.lex('t\\+st').should.eql([{token: 'LITERAL', matched: 't\\+st'}]); | ||
gql.lex('t\\,st').should.eql([{token: 'LITERAL', matched: 't\\,st'}]); | ||
gql.lex('t\\(st').should.eql([{token: 'LITERAL', matched: 't\\(st'}]); | ||
gql.lex('t\\)st').should.eql([{token: 'LITERAL', matched: 't\\)st'}]); | ||
gql.lex('t\\>st').should.eql([{token: 'LITERAL', matched: 't\\>st'}]); | ||
gql.lex('t\\<st').should.eql([{token: 'LITERAL', matched: 't\\<st'}]); | ||
gql.lex('t\\=st').should.eql([{token: 'LITERAL', matched: 't\\=st'}]); | ||
gql.lex('t\\[st').should.eql([{token: 'LITERAL', matched: 't\\[st'}]); | ||
gql.lex('t\\]st').should.eql([{token: 'LITERAL', matched: 't\\]st'}]); | ||
gql.lex('t\\\'st').should.eql([{token: 'LITERAL', matched: 't\\\'st'}]); | ||
gql.lex('t\\"st').should.eql([{token: 'LITERAL', matched: 't\\"st'}]); | ||
}); | ||
@@ -255,30 +255,29 @@ }); | ||
it('should match colon in string as PROP before, literal after', function () { | ||
gql.lex(":test").should.eql([ | ||
{token: "LITERAL", matched: ":test"} | ||
gql.lex(':test').should.eql([ | ||
{token: 'LITERAL', matched: ':test'} | ||
]); | ||
gql.lex("te:st").should.eql([ | ||
{token: "PROP", matched: "te:"}, | ||
{token: "LITERAL", matched: "st"} | ||
gql.lex('te:st').should.eql([ | ||
{token: 'PROP', matched: 'te:'}, | ||
{token: 'LITERAL', matched: 'st'} | ||
]); | ||
gql.lex("test:").should.eql([ | ||
{token: "PROP", matched: "test:"} | ||
gql.lex('test:').should.eql([ | ||
{token: 'PROP', matched: 'test:'} | ||
]); | ||
}); | ||
it('should only match colon-at-end as PROP if PROP is valPROP', function() { | ||
gql.lex("te!:st").should.eql([ | ||
{token: "LITERAL", matched: "te!:st"} | ||
it('should only match colon-at-end as PROP if PROP is valPROP', function () { | ||
gql.lex('te!:st').should.eql([ | ||
{token: 'LITERAL', matched: 'te!:st'} | ||
]); | ||
gql.lex("post-count:6").should.eql([ | ||
{token: "LITERAL", matched: "post-count:6"} | ||
gql.lex('post-count:6').should.eql([ | ||
{token: 'LITERAL', matched: 'post-count:6'} | ||
]); | ||
gql.lex("post_count:6").should.eql([ | ||
{token: "PROP", matched: "post_count:"}, | ||
{token: "NUMBER", matched: "6"} | ||
gql.lex('post_count:6').should.eql([ | ||
{token: 'PROP', matched: 'post_count:'}, | ||
{token: 'NUMBER', matched: '6'} | ||
]); | ||
}); | ||
@@ -289,27 +288,27 @@ }); | ||
it('can recognise simple STRING', function () { | ||
gql.lex("'magic'").should.eql([{token: "STRING", matched: "'magic'"}]); | ||
gql.lex("'magic mystery'").should.eql([{token: "STRING", matched: "'magic mystery'"}]); | ||
gql.lex("'magic 123'").should.eql([{token: "STRING", matched: "'magic 123'"}]); | ||
gql.lex('\'magic\'').should.eql([{token: 'STRING', matched: '\'magic\''}]); | ||
gql.lex('\'magic mystery\'').should.eql([{token: 'STRING', matched: '\'magic mystery\''}]); | ||
gql.lex('\'magic 123\'').should.eql([{token: 'STRING', matched: '\'magic 123\''}]); | ||
}); | ||
it('can recognise multiple STRING values', function () { | ||
gql.lex("'magic''mystery'").should.eql([ | ||
{token: "STRING", matched: "'magic'"}, | ||
{token: "STRING", matched: "'mystery'"} | ||
gql.lex('\'magic\'\'mystery\'').should.eql([ | ||
{token: 'STRING', matched: '\'magic\''}, | ||
{token: 'STRING', matched: '\'mystery\''} | ||
]); | ||
gql.lex("'magic' 'mystery'").should.eql([ | ||
{token: "STRING", matched: "'magic'"}, | ||
{token: "STRING", matched: "'mystery'"} | ||
gql.lex('\'magic\' \'mystery\'').should.eql([ | ||
{token: 'STRING', matched: '\'magic\''}, | ||
{token: 'STRING', matched: '\'mystery\''} | ||
]); | ||
gql.lex("'magic','mystery'").should.eql([ | ||
{token: "STRING", matched: "'magic'"}, | ||
{token: "OR", matched: ","}, | ||
{token: "STRING", matched: "'mystery'"} | ||
gql.lex('\'magic\',\'mystery\'').should.eql([ | ||
{token: 'STRING', matched: '\'magic\''}, | ||
{token: 'OR', matched: ','}, | ||
{token: 'STRING', matched: '\'mystery\''} | ||
]); | ||
gql.lex("['magic','mystery']").should.eql([ | ||
{token: "LBRACKET", matched: "["}, | ||
{token: "STRING", matched: "'magic'"}, | ||
{token: "OR", matched: ","}, | ||
{token: "STRING", matched: "'mystery'"}, | ||
{token: "RBRACKET", matched: "]"} | ||
gql.lex('[\'magic\',\'mystery\']').should.eql([ | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'STRING', matched: '\'magic\''}, | ||
{token: 'OR', matched: ','}, | ||
{token: 'STRING', matched: '\'mystery\''}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
@@ -319,30 +318,29 @@ }); | ||
it('can recognise STRING with special characters', function () { | ||
gql.lex("'magic+'").should.eql([{token: "STRING", matched: "'magic+'"}]); | ||
gql.lex("'magic,'").should.eql([{token: "STRING", matched: "'magic,'"}]); | ||
gql.lex("'magic-'").should.eql([{token: "STRING", matched: "'magic-'"}]); | ||
gql.lex("'magic>'").should.eql([{token: "STRING", matched: "'magic>'"}]); | ||
gql.lex("'magic<'").should.eql([{token: "STRING", matched: "'magic<'"}]); | ||
gql.lex('\'magic+\'').should.eql([{token: 'STRING', matched: '\'magic+\''}]); | ||
gql.lex('\'magic,\'').should.eql([{token: 'STRING', matched: '\'magic,\''}]); | ||
gql.lex('\'magic-\'').should.eql([{token: 'STRING', matched: '\'magic-\''}]); | ||
gql.lex('\'magic>\'').should.eql([{token: 'STRING', matched: '\'magic>\''}]); | ||
gql.lex('\'magic<\'').should.eql([{token: 'STRING', matched: '\'magic<\''}]); | ||
}); | ||
it('should permit special chars inside a STRING, not including quotes', function () { | ||
gql.lex("'t+st'").should.eql([{token: "STRING", matched: "'t+st'"}]); | ||
gql.lex("'t,st'").should.eql([{token: "STRING", matched: "'t,st'"}]); | ||
gql.lex("'t(st'").should.eql([{token: "STRING", matched: "'t(st'"}]); | ||
gql.lex("'t)st'").should.eql([{token: "STRING", matched: "'t)st'"}]); | ||
gql.lex("'t>st'").should.eql([{token: "STRING", matched: "'t>st'"}]); | ||
gql.lex("'t<st'").should.eql([{token: "STRING", matched: "'t<st'"}]); | ||
gql.lex("'t=st'").should.eql([{token: "STRING", matched: "'t=st'"}]); | ||
gql.lex("'t[st'").should.eql([{token: "STRING", matched: "'t[st'"}]); | ||
gql.lex("'t]st'").should.eql([{token: "STRING", matched: "'t]st'"}]); | ||
gql.lex('\'t+st\'').should.eql([{token: 'STRING', matched: '\'t+st\''}]); | ||
gql.lex('\'t,st\'').should.eql([{token: 'STRING', matched: '\'t,st\''}]); | ||
gql.lex('\'t(st\'').should.eql([{token: 'STRING', matched: '\'t(st\''}]); | ||
gql.lex('\'t)st\'').should.eql([{token: 'STRING', matched: '\'t)st\''}]); | ||
gql.lex('\'t>st\'').should.eql([{token: 'STRING', matched: '\'t>st\''}]); | ||
gql.lex('\'t<st\'').should.eql([{token: 'STRING', matched: '\'t<st\''}]); | ||
gql.lex('\'t=st\'').should.eql([{token: 'STRING', matched: '\'t=st\''}]); | ||
gql.lex('\'t[st\'').should.eql([{token: 'STRING', matched: '\'t[st\''}]); | ||
gql.lex('\'t]st\'').should.eql([{token: 'STRING', matched: '\'t]st\''}]); | ||
}); | ||
it('should NOT permit quotes inside a STRING', function () { | ||
(function () { gql.lex("'t'st'") }).should.throw(lexicalError); | ||
(function () { gql.lex("'t\"st'") }).should.throw(lexicalError); | ||
(function () { gql.lex('\'t\'st\'');}).should.throw(lexicalError); | ||
(function () { gql.lex('\'t"st\'');}).should.throw(lexicalError); | ||
}); | ||
it('should permit escaped quotes inside a String', function () { | ||
gql.lex("'t\\'st'").should.eql([{token: "STRING", matched: "'t\\'st'"}]); | ||
gql.lex("'t\\\"st'").should.eql([{token: "STRING", matched: "'t\\\"st'"}]); | ||
gql.lex('\'t\\\'st\'').should.eql([{token: 'STRING', matched: '\'t\\\'st\''}]); | ||
gql.lex('\'t\\"st\'').should.eql([{token: 'STRING', matched: '\'t\\"st\''}]); | ||
}); | ||
@@ -353,25 +351,24 @@ }); | ||
it('CANNOT match an UNescaped double quote in a LITERAL', function () { | ||
(function () {gql.lex('thing"amabob')}).should.throw(lexicalError); | ||
(function () {gql.lex('thing"amabob');}).should.throw(lexicalError); | ||
}); | ||
it('CANNOT match an UNescaped single quote in a LITERAL', function () { | ||
(function () {gql.lex("thing'amabob")}).should.throw(lexicalError); | ||
(function () {gql.lex('thing\'amabob');}).should.throw(lexicalError); | ||
}); | ||
it('CANNOT match an UNescaped double quote in a STRING', function () { | ||
(function () {gql.lex("'thing\"amabob'")}).should.throw(lexicalError); | ||
(function () {gql.lex('\'thing"amabob\'');}).should.throw(lexicalError); | ||
}); | ||
it('CANNOT match an UNescaped single quote in a STRING', function () { | ||
(function () {gql.lex("'thing'amabob'")}).should.throw(lexicalError); | ||
(function () {gql.lex('\'thing\'amabob\'');}).should.throw(lexicalError); | ||
}); | ||
it('CAN match an escaped double quote in a LITERAL', function () { | ||
gql.lex('thing\\"amabob').should.eql([{token: 'LITERAL', matched: 'thing\\"amabob'}]) | ||
gql.lex('thing\\"amabob').should.eql([{token: 'LITERAL', matched: 'thing\\"amabob'}]); | ||
}); | ||
it('CAN match an escaped single quote in a LITERAL', function () { | ||
gql.lex("thing\\'amabob").should.eql([{token: 'LITERAL', matched: "thing\\'amabob"}]) | ||
gql.lex('thing\\\'amabob').should.eql([{token: 'LITERAL', matched: 'thing\\\'amabob'}]); | ||
}); | ||
it('CAN match an escaped double quote in a STRING', function () { | ||
gql.lex("'thing\\\"amabob'").should.eql([{token: 'STRING', matched: "'thing\\\"amabob'"}]) | ||
gql.lex('\'thing\\"amabob\'').should.eql([{token: 'STRING', matched: '\'thing\\"amabob\''}]); | ||
}); | ||
it('CAN match an escaped single quote in a STRING', function () { | ||
gql.lex("'thing\\'amabob'").should.eql([{token: 'STRING', matched: "'thing\\'amabob'"}]) | ||
gql.lex('\'thing\\\'amabob\'').should.eql([{token: 'STRING', matched: '\'thing\\\'amabob\''}]); | ||
}); | ||
@@ -382,20 +379,20 @@ }); | ||
it('should separate NOT at beginning of literal', function () { | ||
gql.lex("tag:-photo").should.eql([ | ||
{token: "PROP", matched: "tag:"}, | ||
{token: "NOT", matched: "-"}, | ||
{token: "LITERAL", matched: "photo"} | ||
gql.lex('tag:-photo').should.eql([ | ||
{token: 'PROP', matched: 'tag:'}, | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LITERAL', matched: 'photo'} | ||
]); | ||
gql.lex("tag:-photo-graph").should.eql([ | ||
{token: "PROP", matched: "tag:"}, | ||
{token: "NOT", matched: "-"}, | ||
{token: "LITERAL", matched: "photo-graph"} | ||
gql.lex('tag:-photo-graph').should.eql([ | ||
{token: 'PROP', matched: 'tag:'}, | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LITERAL', matched: 'photo-graph'} | ||
]); | ||
gql.lex("tags:[-getting-started]").should.eql([ | ||
{token: "PROP", matched: "tags:"}, | ||
{token: "LBRACKET", matched: "["}, | ||
{token: "NOT", matched: "-"}, | ||
{token: "LITERAL", matched: "getting-started"}, | ||
{token: "RBRACKET", matched: "]"} | ||
gql.lex('tags:[-getting-started]').should.eql([ | ||
{token: 'PROP', matched: 'tags:'}, | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LITERAL', matched: 'getting-started'}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
@@ -405,31 +402,31 @@ }); | ||
it('should permit NOT inside a literal', function () { | ||
gql.lex("tags:getting-started").should.eql([ | ||
{ token: "PROP", matched: "tags:" }, | ||
{ token: "LITERAL", matched: "getting-started" } | ||
gql.lex('tags:getting-started').should.eql([ | ||
{token: 'PROP', matched: 'tags:'}, | ||
{token: 'LITERAL', matched: 'getting-started'} | ||
]); | ||
gql.lex("tags:[getting-started]").should.eql([ | ||
{ token: "PROP", matched: "tags:" }, | ||
{ token: "LBRACKET", matched: "[" }, | ||
{ token: "LITERAL", matched: "getting-started" }, | ||
{ token: "RBRACKET", matched: "]" } | ||
gql.lex('tags:[getting-started]').should.eql([ | ||
{token: 'PROP', matched: 'tags:'}, | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'LITERAL', matched: 'getting-started'}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
gql.lex("tags:-[getting-started]").should.eql([ | ||
{ token: "PROP", matched: "tags:" }, | ||
{ token: "NOT", matched: "-" }, | ||
{ token: "LBRACKET", matched: "[" }, | ||
{ token: "LITERAL", matched: "getting-started" }, | ||
{ token: "RBRACKET", matched: "]" } | ||
gql.lex('tags:-[getting-started]').should.eql([ | ||
{token: 'PROP', matched: 'tags:'}, | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'LITERAL', matched: 'getting-started'}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
gql.lex("id:-1+tags:[getting-started]").should.eql([ | ||
{ token: "PROP", matched: "id:" }, | ||
{ token: "NOT", matched: "-" }, | ||
{ token: "NUMBER", matched: "1" }, | ||
{ token: "AND", matched: "+" }, | ||
{ token: "PROP", matched: "tags:" }, | ||
{ token: "LBRACKET", matched: "[" }, | ||
{ token: "LITERAL", matched: "getting-started" }, | ||
{ token: "RBRACKET", matched: "]" } | ||
gql.lex('id:-1+tags:[getting-started]').should.eql([ | ||
{token: 'PROP', matched: 'id:'}, | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'NUMBER', matched: '1'}, | ||
{token: 'AND', matched: '+'}, | ||
{token: 'PROP', matched: 'tags:'}, | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'LITERAL', matched: 'getting-started'}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
@@ -441,42 +438,40 @@ }); | ||
it('many expressions', function () { | ||
gql.lex("tag:photo+featured:true,tag.count:>5").should.eql([ | ||
{token: "PROP", matched: "tag:"}, | ||
{token: "LITERAL", matched: "photo"}, | ||
{token: "AND", matched: "+" }, | ||
{token: "PROP", matched: "featured:"}, | ||
{token: "TRUE", matched: "true"}, | ||
{token: "OR", matched: "," }, | ||
{token: "PROP", matched: "tag.count:"}, | ||
{token: "GT", matched: ">"}, | ||
{token: "NUMBER", matched: "5"} | ||
gql.lex('tag:photo+featured:true,tag.count:>5').should.eql([ | ||
{token: 'PROP', matched: 'tag:'}, | ||
{token: 'LITERAL', matched: 'photo'}, | ||
{token: 'AND', matched: '+'}, | ||
{token: 'PROP', matched: 'featured:'}, | ||
{token: 'TRUE', matched: 'true'}, | ||
{token: 'OR', matched: ','}, | ||
{token: 'PROP', matched: 'tag.count:'}, | ||
{token: 'GT', matched: '>'}, | ||
{token: 'NUMBER', matched: '5'} | ||
]); | ||
//gql.lex("tag:photo+image:-null,tag.count:>5").should.eql(); | ||
// gql.lex("tag:photo+image:-null,tag.count:>5").should.eql(); | ||
}); | ||
it('grouped expressions', function () { | ||
// gql.lex("author:-joe+(tag:photo,image:-null,featured:true)").should.eql(); | ||
// gql.lex("author:-joe+(tag:photo,image:-null,featured:true)").should.eql(); | ||
}); | ||
it('in expressions', function () { | ||
gql.lex("author:-joe+tag:[photo,video]").should.eql([ | ||
{token: "PROP", matched: "author:"}, | ||
{token: "NOT", matched: "-"}, | ||
{token: "LITERAL", matched: "joe"}, | ||
{token: "AND", matched: "+"}, | ||
{token: "PROP", matched: "tag:"}, | ||
{token: "LBRACKET", matched: "["}, | ||
{token: "LITERAL", matched: "photo"}, | ||
{token: "OR", matched: ","}, | ||
{token: "LITERAL", matched: "video"}, | ||
{token: "RBRACKET", matched: "]"} | ||
]); | ||
gql.lex('author:-joe+tag:[photo,video]').should.eql([ | ||
{token: 'PROP', matched: 'author:'}, | ||
{token: 'NOT', matched: '-'}, | ||
{token: 'LITERAL', matched: 'joe'}, | ||
{token: 'AND', matched: '+'}, | ||
{token: 'PROP', matched: 'tag:'}, | ||
{token: 'LBRACKET', matched: '['}, | ||
{token: 'LITERAL', matched: 'photo'}, | ||
{token: 'OR', matched: ','}, | ||
{token: 'LITERAL', matched: 'video'}, | ||
{token: 'RBRACKET', matched: ']'} | ||
]); | ||
// gql.lex("author:-joe+tag:-[photo,video]").should.eql(); | ||
// gql.lex("author:-joe+tag:-[photo,video]").should.eql(); | ||
// gql.lex("author:-joe+tag:[photo,video]+post.count:>5+post.count:<100").should.eql(); | ||
// gql.lex("author:-joe+tag:[photo,video]+post.count:>5+post.count:<100").should.eql(); | ||
}); | ||
}); | ||
}); | ||
@@ -0,1 +1,2 @@ | ||
/* globals describe, beforeEach, afterEach, it */ | ||
var should = require('should'), | ||
@@ -5,3 +6,3 @@ sinon = require('sinon'), | ||
sandbox = sinon.sandbox.create(); | ||
sandbox = sinon.sandbox.create(), | ||
@@ -87,5 +88,5 @@ lodashStmt = require('../lib/lodash-stmt'); | ||
eachStatement([ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: "=", value: "photo", prop: "tag", func: "and"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{op: '=', value: 'photo', prop: 'tag', func: 'and'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], single, group); | ||
@@ -101,13 +102,13 @@ | ||
eachStatement([ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
], single); | ||
single.callCount.should.eql(3); | ||
single.getCall(0).calledWith({op: "!=", value: "joe", prop: "author"}).should.eql(true); | ||
single.getCall(1).calledWith({op: "=", value: "photo", prop: "tag"}).should.eql(true); | ||
single.getCall(2).calledWith({op: "=", value: "video", prop: "tag", func: "or"}).should.eql(true); | ||
single.getCall(0).calledWith({op: '!=', value: 'joe', prop: 'author'}).should.eql(true); | ||
single.getCall(1).calledWith({op: '=', value: 'photo', prop: 'tag'}).should.eql(true); | ||
single.getCall(2).calledWith({op: '=', value: 'video', prop: 'tag', func: 'or'}).should.eql(true); | ||
}); | ||
@@ -119,19 +120,19 @@ | ||
eachStatement([ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "published", prop: "status", func: "and"}, | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'published', prop: 'status', func: 'and'}, | ||
{group: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
], func: 'and'} | ||
], single); | ||
single.callCount.should.eql(5); | ||
single.getCall(0).calledWith({op: "=", value: false, prop: "page"}).should.eql(true); | ||
single.getCall(1).calledWith({op: "=", value: "published", prop: "status", func: "and"}).should.eql(true); | ||
single.getCall(2).calledWith({op: "!=", value: "joe", prop: "author"}).should.eql(true); | ||
single.getCall(3).calledWith({op: "=", value: "photo", prop: "tag"}).should.eql(true); | ||
single.getCall(4).calledWith({op: "=", value: "video", prop: "tag", func: "or"}).should.eql(true); | ||
single.getCall(0).calledWith({op: '=', value: false, prop: 'page'}).should.eql(true); | ||
single.getCall(1).calledWith({op: '=', value: 'published', prop: 'status', func: 'and'}).should.eql(true); | ||
single.getCall(2).calledWith({op: '!=', value: 'joe', prop: 'author'}).should.eql(true); | ||
single.getCall(3).calledWith({op: '=', value: 'photo', prop: 'tag'}).should.eql(true); | ||
single.getCall(4).calledWith({op: '=', value: 'video', prop: 'tag', func: 'or'}).should.eql(true); | ||
}); | ||
@@ -149,19 +150,18 @@ | ||
testFunc([ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
]); | ||
single.callCount.should.eql(3); | ||
single.getCall(0).calledWith({op: "!=", value: "joe", prop: "author"}).should.eql(true); | ||
single.getCall(1).calledWith({op: "=", value: "photo", prop: "tag"}).should.eql(true); | ||
single.getCall(2).calledWith({op: "=", value: "video", prop: "tag", func: "or"}).should.eql(true); | ||
single.getCall(0).calledWith({op: '!=', value: 'joe', prop: 'author'}).should.eql(true); | ||
single.getCall(1).calledWith({op: '=', value: 'photo', prop: 'tag'}).should.eql(true); | ||
single.getCall(2).calledWith({op: '=', value: 'video', prop: 'tag', func: 'or'}).should.eql(true); | ||
group.callCount.should.eql(1); | ||
group.getCall(0).calledWith({group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"}).should.eql(true); | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'}).should.eql(true); | ||
}); | ||
@@ -179,35 +179,35 @@ | ||
testFunc([ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "published", prop: "status", func: "and"}, | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'published', prop: 'status', func: 'and'}, | ||
{group: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
], func: 'and'} | ||
]); | ||
single.callCount.should.eql(5); | ||
single.getCall(0).calledWith({op: "=", value: false, prop: "page"}).should.eql(true); | ||
single.getCall(1).calledWith({op: "=", value: "published", prop: "status", func: "and"}).should.eql(true); | ||
single.getCall(2).calledWith({op: "!=", value: "joe", prop: "author"}).should.eql(true); | ||
single.getCall(3).calledWith({op: "=", value: "photo", prop: "tag"}).should.eql(true); | ||
single.getCall(4).calledWith({op: "=", value: "video", prop: "tag", func: "or"}).should.eql(true); | ||
single.getCall(0).calledWith({op: '=', value: false, prop: 'page'}).should.eql(true); | ||
single.getCall(1).calledWith({op: '=', value: 'published', prop: 'status', func: 'and'}).should.eql(true); | ||
single.getCall(2).calledWith({op: '!=', value: 'joe', prop: 'author'}).should.eql(true); | ||
single.getCall(3).calledWith({op: '=', value: 'photo', prop: 'tag'}).should.eql(true); | ||
single.getCall(4).calledWith({op: '=', value: 'video', prop: 'tag', func: 'or'}).should.eql(true); | ||
group.callCount.should.eql(2); | ||
group.getCall(0).calledWith({group: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{ | ||
group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and" | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and' | ||
} | ||
], func: "and"}).should.eql(true); | ||
], func: 'and'}).should.eql(true); | ||
group.getCall(1).calledWith({group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"}).should.eql(true); | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'}).should.eql(true); | ||
}); | ||
@@ -276,13 +276,12 @@ }); | ||
var statements = [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
]; | ||
findStatement(statements, {value: 'photo'}).should.eql(true); | ||
findStatement(statements, {op: "=", value: "photo", prop: "tag"}, 'value').should.eql(true); | ||
findStatement(statements, {op: "=", value: "photo", prop: "tag"}, ['value', 'prop']).should.eql(true); | ||
findStatement(statements, {op: '=', value: 'photo', prop: 'tag'}, 'value').should.eql(true); | ||
findStatement(statements, {op: '=', value: 'photo', prop: 'tag'}, ['value', 'prop']).should.eql(true); | ||
findStatement(statements, {prop: /^tag/}).should.eql(true); | ||
@@ -299,3 +298,3 @@ findStatement(statements, {prop: 'page'}).should.eql(false); | ||
return lodashStmt.matchStatement(statement, fields ? _.pick(match, fields) : match); | ||
} | ||
}; | ||
}; | ||
@@ -325,14 +324,14 @@ | ||
var statements = [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
]; | ||
rejectStatements(statements, testFunction({value: 'video'})).should.eql([ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'} | ||
], func: 'and'} | ||
]); | ||
@@ -343,11 +342,11 @@ }); | ||
var statements = [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and'} | ||
]; | ||
rejectStatements(statements, testFunction({prop: 'tag'})).should.eql([ | ||
{op: "!=", value: "joe", prop: "author"} | ||
{op: '!=', value: 'joe', prop: 'author'} | ||
]); | ||
@@ -358,8 +357,8 @@ }); | ||
var statements = [ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "cameron", prop: "author", func: "or"} | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'cameron', prop: 'author', func: 'or'} | ||
]; | ||
rejectStatements(statements, testFunction({prop: "page"})).should.eql([ | ||
{op: "=", value: "cameron", prop: "author"} | ||
rejectStatements(statements, testFunction({prop: 'page'})).should.eql([ | ||
{op: '=', value: 'cameron', prop: 'author'} | ||
]); | ||
@@ -370,16 +369,16 @@ }); | ||
var statements = [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"}, | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'}, | ||
{group: [ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "cameron", prop: "author", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'cameron', prop: 'author', func: 'or'} | ||
], func: 'and'} | ||
]; | ||
rejectStatements(statements, testFunction({prop: "page"})).should.eql( [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"}, | ||
rejectStatements(statements, testFunction({prop: 'page'})).should.eql([ | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'}, | ||
{group: [ | ||
{op: "=", value: "cameron", prop: "author"} | ||
], func: "and"} | ||
{op: '=', value: 'cameron', prop: 'author'} | ||
], func: 'and'} | ||
]); | ||
@@ -391,15 +390,15 @@ }); | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
]}, | ||
{group: [ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "cameron", prop: "author", func: "or"} | ||
], func: "and"} | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'cameron', prop: 'author', func: 'or'} | ||
], func: 'and'} | ||
]; | ||
rejectStatements(statements, testFunction({prop: "tag"})).should.eql([ | ||
rejectStatements(statements, testFunction({prop: 'tag'})).should.eql([ | ||
{group: [ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "cameron", prop: "author", func: "or"} | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'cameron', prop: 'author', func: 'or'} | ||
]} | ||
@@ -412,12 +411,12 @@ ]); | ||
{group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
]}, | ||
{op: "=", value: false, prop: "page", func: "and"}, | ||
{op: "=", value: "cameron", prop: "author", func: "or"} | ||
{op: '=', value: false, prop: 'page', func: 'and'}, | ||
{op: '=', value: 'cameron', prop: 'author', func: 'or'} | ||
]; | ||
rejectStatements(statements, testFunction({prop: "tag"})).should.eql([ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "cameron", prop: "author", func: "or"} | ||
rejectStatements(statements, testFunction({prop: 'tag'})).should.eql([ | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'cameron', prop: 'author', func: 'or'} | ||
]); | ||
@@ -433,3 +432,3 @@ }); | ||
var result = mergeStatements(); | ||
result.should.eql({statements: []}) | ||
result.should.eql({statements: []}); | ||
}); | ||
@@ -439,3 +438,3 @@ | ||
var result = mergeStatements(undefined, undefined); | ||
result.should.eql({statements: []}) | ||
result.should.eql({statements: []}); | ||
}); | ||
@@ -445,3 +444,3 @@ | ||
var result = mergeStatements(null, null); | ||
result.should.eql({statements: []}) | ||
result.should.eql({statements: []}); | ||
}); | ||
@@ -452,10 +451,10 @@ }); | ||
var result = mergeStatements( | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published"} | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published'} | ||
); | ||
result.should.eql({statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
]}) | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}); | ||
}); | ||
@@ -466,8 +465,8 @@ | ||
null, | ||
{prop: "status", op: "=", value: "published"} | ||
{prop: 'status', op: '=', value: 'published'} | ||
); | ||
result.should.eql({statements: [ | ||
{prop: "status", op: "=", value: "published"} | ||
]}) | ||
{prop: 'status', op: '=', value: 'published'} | ||
]}); | ||
}); | ||
@@ -478,8 +477,8 @@ | ||
undefined, | ||
{prop: "status", op: "=", value: "published"} | ||
{prop: 'status', op: '=', value: 'published'} | ||
); | ||
result.should.eql({statements: [ | ||
{prop: "status", op: "=", value: "published"} | ||
]}) | ||
{prop: 'status', op: '=', value: 'published'} | ||
]}); | ||
}); | ||
@@ -489,8 +488,8 @@ | ||
var obj1 = {statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}, | ||
obj2 = {statements: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
]}, | ||
@@ -500,7 +499,7 @@ result = mergeStatements(obj1, obj2); | ||
result.should.eql({statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"}, | ||
{op: "=", value: "photo", prop: "tag", func: "and"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
]}) | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'}, | ||
{op: '=', value: 'photo', prop: 'tag', func: 'and'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
]}); | ||
}); | ||
@@ -510,4 +509,4 @@ | ||
var obj1 = {statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}, | ||
@@ -518,5 +517,5 @@ obj2 = {statements: []}, | ||
result.should.eql({statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
]}) | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}); | ||
}); | ||
@@ -526,4 +525,4 @@ | ||
var obj1 = {statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}, | ||
@@ -534,5 +533,5 @@ obj2 = null, | ||
result.should.eql({statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
]}) | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}); | ||
}); | ||
@@ -542,12 +541,12 @@ | ||
var obj1 = {statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}, | ||
obj2 = undefined, | ||
obj2, | ||
result = mergeStatements(obj1, obj2); | ||
result.should.eql({statements: [ | ||
{prop: "page", op: "=", value: false}, | ||
{prop: "status", op: "=", value: "published", func: "and"} | ||
]}) | ||
{prop: 'page', op: '=', value: false}, | ||
{prop: 'status', op: '=', value: 'published', func: 'and'} | ||
]}); | ||
}); | ||
@@ -572,11 +571,11 @@ }); | ||
printStatements([ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: "=", value: "photo", prop: "tag", func: "and"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{op: '=', value: 'photo', prop: 'tag', func: 'and'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
]); | ||
consoleSpy.callCount.should.eql(3); | ||
consoleSpy.getCall(0).args.should.eql(['', {op: "!=", value: "joe", prop: "author"}]); | ||
consoleSpy.getCall(1).args.should.eql(['', {op: "=", value: "photo", prop: "tag", func: "and"}]); | ||
consoleSpy.getCall(2).args.should.eql(['', {op: "=", value: "video", prop: "tag", func: "or"}]); | ||
consoleSpy.getCall(0).args.should.eql(['', {op: '!=', value: 'joe', prop: 'author'}]); | ||
consoleSpy.getCall(1).args.should.eql(['', {op: '=', value: 'photo', prop: 'tag', func: 'and'}]); | ||
consoleSpy.getCall(2).args.should.eql(['', {op: '=', value: 'video', prop: 'tag', func: 'or'}]); | ||
}); | ||
@@ -588,8 +587,8 @@ | ||
printStatements([ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{ | ||
group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and" | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and' | ||
} | ||
@@ -599,6 +598,6 @@ ]); | ||
consoleSpy.callCount.should.eql(4); | ||
consoleSpy.getCall(0).args.should.eql(['', {op: "!=", value: "joe", prop: "author"}]); | ||
consoleSpy.getCall(0).args.should.eql(['', {op: '!=', value: 'joe', prop: 'author'}]); | ||
consoleSpy.getCall(1).args.should.eql(['', 'group', 'and']); | ||
consoleSpy.getCall(2).args.should.eql([' ', {op: "=", value: "photo", prop: "tag"}]); | ||
consoleSpy.getCall(3).args.should.eql([' ', {op: "=", value: "video", prop: "tag", func: "or"}]); | ||
consoleSpy.getCall(2).args.should.eql([' ', {op: '=', value: 'photo', prop: 'tag'}]); | ||
consoleSpy.getCall(3).args.should.eql([' ', {op: '=', value: 'video', prop: 'tag', func: 'or'}]); | ||
}); | ||
@@ -610,14 +609,14 @@ | ||
printStatements([ | ||
{op: "=", value: false, prop: "page"}, | ||
{op: "=", value: "published", prop: "status", func: "and"}, | ||
{op: '=', value: false, prop: 'page'}, | ||
{op: '=', value: 'published', prop: 'status', func: 'and'}, | ||
{ | ||
group: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{ | ||
group: [ | ||
{op: "=", value: "photo", prop: "tag"}, | ||
{op: "=", value: "video", prop: "tag", func: "or"} | ||
], func: "and" | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: 'video', prop: 'tag', func: 'or'} | ||
], func: 'and' | ||
} | ||
], func: "and" | ||
], func: 'and' | ||
} | ||
@@ -627,12 +626,11 @@ ]); | ||
consoleSpy.callCount.should.eql(7); | ||
consoleSpy.getCall(0).args.should.eql(['', {op: "=", value: false, prop: "page"}]); | ||
consoleSpy.getCall(1).args.should.eql(['', {op: "=", value: "published", prop: "status", func: "and"}]); | ||
consoleSpy.getCall(0).args.should.eql(['', {op: '=', value: false, prop: 'page'}]); | ||
consoleSpy.getCall(1).args.should.eql(['', {op: '=', value: 'published', prop: 'status', func: 'and'}]); | ||
consoleSpy.getCall(2).args.should.eql(['', 'group', 'and']); | ||
consoleSpy.getCall(3).args.should.eql([' ', {op: "!=", value: "joe", prop: "author"}]); | ||
consoleSpy.getCall(3).args.should.eql([' ', {op: '!=', value: 'joe', prop: 'author'}]); | ||
consoleSpy.getCall(4).args.should.eql([' ', 'group', 'and']); | ||
consoleSpy.getCall(5).args.should.eql([' ', {op: "=", value: "photo", prop: "tag"}]); | ||
consoleSpy.getCall(6).args.should.eql([' ', {op: "=", value: "video", prop: "tag", func: "or"}]); | ||
consoleSpy.getCall(5).args.should.eql([' ', {op: '=', value: 'photo', prop: 'tag'}]); | ||
consoleSpy.getCall(6).args.should.eql([' ', {op: '=', value: 'video', prop: 'tag', func: 'or'}]); | ||
}); | ||
}); | ||
}); | ||
@@ -0,1 +1,3 @@ | ||
/* globals describe, it */ | ||
/* jshint unused:false */ | ||
var should = require('should'), | ||
@@ -5,21 +7,21 @@ gql = require('../lib/gql'); | ||
describe('Parser', function () { | ||
var parserError = /^Parse error on line 1:/; | ||
var parserError = /^Query Error: unexpected character in filter at char/; | ||
describe('Operators', function () { | ||
it('can parse standard equals', function () { | ||
gql.parse("count:5").should.eql({ | ||
gql.parse('count:5').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "=", "value": 5} | ||
{prop: 'count', op: '=', value: 5} | ||
] | ||
}); | ||
gql.parse("tag:getting-started").should.eql({ | ||
gql.parse('tag:getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "=", "value": "getting-started"} | ||
{prop: 'tag', op: '=', value: 'getting-started'} | ||
] | ||
}); | ||
gql.parse("author:'Joe Bloggs'").should.eql({ | ||
gql.parse('author:\'Joe Bloggs\'').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "=", "value": "Joe Bloggs"} | ||
{prop: 'author', op: '=', value: 'Joe Bloggs'} | ||
] | ||
@@ -30,17 +32,17 @@ }); | ||
it('can parse not equals', function () { | ||
gql.parse("count:-5").should.eql({ | ||
gql.parse('count:-5').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "!=", "value": 5} | ||
{prop: 'count', op: '!=', value: 5} | ||
] | ||
}); | ||
gql.parse("tag:-getting-started").should.eql({ | ||
gql.parse('tag:-getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "!=", "value": "getting-started"} | ||
{prop: 'tag', op: '!=', value: 'getting-started'} | ||
] | ||
}); | ||
gql.parse("author:-'Joe Bloggs'").should.eql({ | ||
gql.parse('author:-\'Joe Bloggs\'').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "!=", "value": "Joe Bloggs"} | ||
{prop: 'author', op: '!=', value: 'Joe Bloggs'} | ||
] | ||
@@ -51,17 +53,17 @@ }); | ||
it('can parse greater than', function () { | ||
gql.parse("count:>5").should.eql({ | ||
gql.parse('count:>5').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": ">", "value": 5} | ||
{prop: 'count', op: '>', value: 5} | ||
] | ||
}); | ||
gql.parse("tag:>getting-started").should.eql({ | ||
gql.parse('tag:>getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": ">", "value": "getting-started"} | ||
{prop: 'tag', op: '>', value: 'getting-started'} | ||
] | ||
}); | ||
gql.parse("author:>'Joe Bloggs'").should.eql({ | ||
gql.parse('author:>\'Joe Bloggs\'').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": ">", "value": "Joe Bloggs"} | ||
{prop: 'author', op: '>', value: 'Joe Bloggs'} | ||
] | ||
@@ -72,17 +74,17 @@ }); | ||
it('can parse less than', function () { | ||
gql.parse("count:<5").should.eql({ | ||
gql.parse('count:<5').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "<", "value": 5} | ||
{prop: 'count', op: '<', value: 5} | ||
] | ||
}); | ||
gql.parse("tag:<getting-started").should.eql({ | ||
gql.parse('tag:<getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "<", "value": "getting-started"} | ||
{prop: 'tag', op: '<', value: 'getting-started'} | ||
] | ||
}); | ||
gql.parse("author:<'Joe Bloggs'").should.eql({ | ||
gql.parse('author:<\'Joe Bloggs\'').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "<", "value": "Joe Bloggs"} | ||
{prop: 'author', op: '<', value: 'Joe Bloggs'} | ||
] | ||
@@ -93,17 +95,17 @@ }); | ||
it('can parse greater than or equals', function () { | ||
gql.parse("count:>=5").should.eql({ | ||
gql.parse('count:>=5').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": ">=", "value": 5} | ||
{prop: 'count', op: '>=', value: 5} | ||
] | ||
}); | ||
gql.parse("tag:>=getting-started").should.eql({ | ||
gql.parse('tag:>=getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": ">=", "value": "getting-started"} | ||
{prop: 'tag', op: '>=', value: 'getting-started'} | ||
] | ||
}); | ||
gql.parse("author:>='Joe Bloggs'").should.eql({ | ||
gql.parse('author:>=\'Joe Bloggs\'').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": ">=", "value": "Joe Bloggs"} | ||
{prop: 'author', op: '>=', value: 'Joe Bloggs'} | ||
] | ||
@@ -114,17 +116,17 @@ }); | ||
it('can parse less than or equals', function () { | ||
gql.parse("count:<=5").should.eql({ | ||
gql.parse('count:<=5').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "<=", "value": 5} | ||
{prop: 'count', op: '<=', value: 5} | ||
] | ||
}); | ||
gql.parse("tag:<=getting-started").should.eql({ | ||
gql.parse('tag:<=getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "<=", "value": "getting-started"} | ||
{prop: 'tag', op: '<=', value: 'getting-started'} | ||
] | ||
}); | ||
gql.parse("author:<='Joe Bloggs'").should.eql({ | ||
gql.parse('author:<=\'Joe Bloggs\'').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "<=", "value": "Joe Bloggs"} | ||
{prop: 'author', op: '<=', value: 'Joe Bloggs'} | ||
] | ||
@@ -135,17 +137,17 @@ }); | ||
it('can parse IN with single value', function () { | ||
gql.parse("count:[5]").should.eql({ | ||
gql.parse('count:[5]').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "IN", "value": [5]} | ||
{prop: 'count', op: 'IN', value: [5]} | ||
] | ||
}); | ||
gql.parse("tag:[getting-started]").should.eql({ | ||
gql.parse('tag:[getting-started]').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "IN", "value": ["getting-started"]} | ||
{prop: 'tag', op: 'IN', value: ['getting-started']} | ||
] | ||
}); | ||
gql.parse("author:['Joe Bloggs']").should.eql({ | ||
gql.parse('author:[\'Joe Bloggs\']').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "IN", "value": ["Joe Bloggs"]} | ||
{prop: 'author', op: 'IN', value: ['Joe Bloggs']} | ||
] | ||
@@ -156,17 +158,17 @@ }); | ||
it('can parse NOT IN with single value', function () { | ||
gql.parse("count:-[5]").should.eql({ | ||
gql.parse('count:-[5]').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "NOT IN", "value": [5]} | ||
{prop: 'count', op: 'NOT IN', value: [5]} | ||
] | ||
}); | ||
gql.parse("tag:-[getting-started]").should.eql({ | ||
gql.parse('tag:-[getting-started]').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "NOT IN", "value": ["getting-started"]} | ||
{prop: 'tag', op: 'NOT IN', value: ['getting-started']} | ||
] | ||
}); | ||
gql.parse("author:-['Joe Bloggs']").should.eql({ | ||
gql.parse('author:-[\'Joe Bloggs\']').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "NOT IN", "value": ["Joe Bloggs"]} | ||
{prop: 'author', op: 'NOT IN', value: ['Joe Bloggs']} | ||
] | ||
@@ -177,17 +179,17 @@ }); | ||
it('can parse IN with multiple values', function () { | ||
gql.parse("count:[5, 8, 12]").should.eql({ | ||
gql.parse('count:[5, 8, 12]').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "IN", "value": [5, 8, 12]} | ||
{prop: 'count', op: 'IN', value: [5, 8, 12]} | ||
] | ||
}); | ||
gql.parse("tag:[getting-started, ghost, really-long-1]").should.eql({ | ||
gql.parse('tag:[getting-started, ghost, really-long-1]').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "IN", "value": ["getting-started", "ghost", "really-long-1"]} | ||
{prop: 'tag', op: 'IN', value: ['getting-started', 'ghost', 'really-long-1']} | ||
] | ||
}); | ||
gql.parse("author:['Joe Bloggs', 'John O\\\'Nolan', 'Hello World']").should.eql({ | ||
gql.parse('author:[\'Joe Bloggs\', \'John O\\\'Nolan\', \'Hello World\']').should.eql({ | ||
statements: [ | ||
{"prop": "author", "op": "IN", "value": ["Joe Bloggs", "John O\'Nolan", "Hello World"]} | ||
{prop: 'author', op: 'IN', value: ['Joe Bloggs', 'John O\'Nolan', 'Hello World']} | ||
] | ||
@@ -198,17 +200,17 @@ }); | ||
it('can parse NOT IN with single value', function () { | ||
gql.parse("count:-[5, 8, 12]").should.eql({ | ||
gql.parse('count:-[5, 8, 12]').should.eql({ | ||
statements: [ | ||
{"prop": "count", "op": "NOT IN", "value": [5, 8, 12]} | ||
{prop: 'count', op: 'NOT IN', value: [5, 8, 12]} | ||
] | ||
}); | ||
gql.parse("tag:-[getting-started, ghost, really-long-1]").should.eql({ | ||
gql.parse('tag:-[getting-started, ghost, really-long-1]').should.eql({ | ||
statements: [ | ||
{"prop": "tag", "op": "NOT IN", "value": ["getting-started", "ghost", "really-long-1"]} | ||
{prop: 'tag', op: 'NOT IN', value: ['getting-started', 'ghost', 'really-long-1']} | ||
] | ||
}); | ||
gql.parse("author:-['Joe Bloggs', 'John O\\\'Nolan', 'Hello World']").should.eql({ | ||
gql.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"]} | ||
{prop: 'author', op: 'NOT IN', value: ['Joe Bloggs', 'John O\'Nolan', 'Hello World']} | ||
] | ||
@@ -223,5 +225,5 @@ }); | ||
statements: [ | ||
{"prop": "image", "op": "IS", "value": null} | ||
{prop: 'image', op: 'IS', value: null} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -232,5 +234,5 @@ | ||
statements: [ | ||
{"prop": "image", "op": "IS NOT", "value": null} | ||
{prop: 'image', op: 'IS NOT', value: null} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -241,5 +243,5 @@ | ||
statements: [ | ||
{"prop": "featured", "op": "=", "value": true} | ||
{prop: 'featured', op: '=', value: true} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -250,5 +252,5 @@ | ||
statements: [ | ||
{"prop": "featured", "op": "!=", "value": true} | ||
{prop: 'featured', op: '!=', value: true} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -259,5 +261,5 @@ | ||
statements: [ | ||
{"prop": "featured", "op": "=", "value": false} | ||
{prop: 'featured', op: '=', value: false} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -268,5 +270,5 @@ | ||
statements: [ | ||
{"prop": "featured", "op": "!=", "value": false} | ||
{prop: 'featured', op: '!=', value: false} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -277,5 +279,5 @@ | ||
statements: [ | ||
{"prop": "count", "op": "=", "value": 5} | ||
{prop: 'count', op: '=', value: 5} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -286,5 +288,5 @@ | ||
statements: [ | ||
{"prop": "count", "op": "!=", "value": 5} | ||
{prop: 'count', op: '!=', value: 5} | ||
] | ||
}) | ||
}); | ||
}); | ||
@@ -295,14 +297,13 @@ }); | ||
it('should parse simple id & value combos', function () { | ||
gql.parse("id:3").should.eql({ | ||
gql.parse('id:3').should.eql({ | ||
statements: [ | ||
{"prop": "id", "op": "=", "value": 3} | ||
{prop: 'id', op: '=', value: 3} | ||
] | ||
}); | ||
gql.parse("slug:getting-started").should.eql({ | ||
gql.parse('slug:getting-started').should.eql({ | ||
statements: [ | ||
{"prop": "slug", "op": "=", "value": "getting-started"} | ||
{prop: 'slug', op: '=', value: 'getting-started'} | ||
] | ||
}); | ||
}); | ||
@@ -313,15 +314,15 @@ }); | ||
it('many expressions', function () { | ||
gql.parse("tag:photo+featured:true,tag.count:>5").should.eql({ | ||
gql.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"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: '=', value: true, prop: 'featured', func: 'and'}, | ||
{op: '>', value: 5, prop: 'tag.count', func: 'or'} | ||
] | ||
}); | ||
gql.parse("tag:photo+image:-null,tag.count:>5").should.eql({ | ||
gql.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"} | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: 'IS NOT', value: null, prop: 'image', func: 'and'}, | ||
{op: '>', value: 5, prop: 'tag.count', func: 'or'} | ||
] | ||
@@ -332,11 +333,11 @@ }); | ||
it('grouped expressions', function () { | ||
gql.parse("author:-joe+(tag:photo,image:-null,featured:true)").should.eql({ | ||
gql.parse('author:-joe+(tag:photo,image:-null,featured:true)').should.eql({ | ||
statements: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{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" | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: 'IS NOT', value: null, prop: 'image', func: 'or'}, | ||
{op: '=', value: true, prop: 'featured', func: 'or'} | ||
], func: 'and' | ||
} | ||
@@ -346,24 +347,24 @@ ] | ||
gql.parse("(tag:photo,image:-null,featured:true)+author:-joe").should.eql({ | ||
gql.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: '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"} | ||
{op: '!=', value: 'joe', prop: 'author', func: 'and'} | ||
] | ||
}); | ||
gql.parse("author:-joe,(tag:photo,image:-null,featured:true)").should.eql({ | ||
gql.parse('author:-joe,(tag:photo,image:-null,featured:true)').should.eql({ | ||
statements: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{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" | ||
{op: '=', value: 'photo', prop: 'tag'}, | ||
{op: 'IS NOT', value: null, prop: 'image', func: 'or'}, | ||
{op: '=', value: true, prop: 'featured', func: 'or'} | ||
], func: 'or' | ||
} | ||
@@ -373,12 +374,12 @@ ] | ||
gql.parse("(tag:photo,image:-null,featured:false),author:-joe").should.eql({ | ||
gql.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: '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"} | ||
{op: '!=', value: 'joe', prop: 'author', func: 'or'} | ||
] | ||
@@ -389,22 +390,22 @@ }); | ||
it('in expressions', function () { | ||
gql.parse("author:-joe+tag:[photo,video]").should.eql({ | ||
gql.parse('author:-joe+tag:[photo,video]').should.eql({ | ||
statements: [ | ||
{op: "!=", value: "joe", prop: "author"}, | ||
{op: "IN", value: ["photo", "video"], prop: "tag", func: "and"} | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{op: 'IN', value: ['photo', 'video'], prop: 'tag', func: 'and'} | ||
] | ||
}); | ||
gql.parse("author:-joe+tag:-[photo,video,audio]").should.eql({ | ||
gql.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"} | ||
{op: '!=', value: 'joe', prop: 'author'}, | ||
{op: 'NOT IN', value: ['photo', 'video', 'audio'], prop: 'tag', func: 'and'} | ||
] | ||
}); | ||
gql.parse("author:-joe+tag:[photo,video,magic,\'audio\']+post.count:>5+post.count:<100").should.eql({ | ||
gql.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"} | ||
{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'} | ||
] | ||
@@ -417,8 +418,8 @@ }); | ||
it('will ignore whitespace in expressions', function () { | ||
gql.parse("count: -5").should.eql(gql.parse("count:-5")); | ||
gql.parse("author: -joe + tag: [photo, video]").should.eql(gql.parse("author:-joe+tag:[photo,video]")); | ||
gql.parse('count: -5').should.eql(gql.parse('count:-5')); | ||
gql.parse('author: -joe + tag: [photo, video]').should.eql(gql.parse('author:-joe+tag:[photo,video]')); | ||
}); | ||
it('will not ignore whitespace in Strings', function () { | ||
gql.parse("author:'Hello World'").should.not.eql(gql.parse("author:'HelloWorld'")); | ||
gql.parse('author:\'Hello World\'').should.not.eql(gql.parse('author:\'HelloWorld\'')); | ||
}); | ||
@@ -429,27 +430,27 @@ }); | ||
it('CANNOT parse characters outside of a STRING value', function () { | ||
(function () { gql.parse("tag:'My Tag'-") }).should.throw(parserError); | ||
(function () { gql.parse('tag:\'My Tag\'-');}).should.throw(parserError); | ||
}); | ||
it('CANNOT parse property - operator - value in wrong order', function () { | ||
(function () { gql.parse("'My Tag':tag") }).should.throw(parserError); | ||
(function () { gql.parse("5>:tag") }).should.throw(parserError); | ||
(function () { gql.parse('\'My Tag\':tag');}).should.throw(parserError); | ||
(function () { gql.parse('5>:tag');}).should.throw(parserError); | ||
}); | ||
it('CANNOT parse combination without filter expression', function () { | ||
(function () { gql.parse("count:3+") }).should.throw(parserError); | ||
(function () { gql.parse(",count:3") }).should.throw(parserError); | ||
(function () { gql.parse('count:3+');}).should.throw(parserError); | ||
(function () { gql.parse(',count:3');}).should.throw(parserError); | ||
}); | ||
it('CANNOT parse incomplete group', function () { | ||
(function () { gql.parse("id:5,(count:3") }).should.throw(parserError); | ||
(function () { gql.parse("count:3)") }).should.throw(parserError); | ||
(function () { gql.parse("id:5(count:3)") }).should.throw(parserError); | ||
(function () { gql.parse('id:5,(count:3');}).should.throw(parserError); | ||
(function () { gql.parse('count:3)');}).should.throw(parserError); | ||
(function () { gql.parse('id:5(count:3)');}).should.throw(parserError); | ||
}); | ||
it('CANNOT parse invalid IN expression', function () { | ||
(function () { gql.parse("id:[test+ing]") }).should.throw(parserError); | ||
(function () { gql.parse("id:[test") }).should.throw(parserError); | ||
(function () { gql.parse("id:test,ing]") }).should.throw(parserError); | ||
}) | ||
(function () { gql.parse('id:[test+ing]');}).should.throw(parserError); | ||
(function () { gql.parse('id:[test');}).should.throw(parserError); | ||
(function () { gql.parse('id:test,ing]');}).should.throw(parserError); | ||
}); | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
127585
23
127
9
2662