bifocal/node_modules/@tryghost/nql/test/unit/query.test.js

103 lines
4.6 KiB
JavaScript

require('../utils');
const nql = require('../../');
const knex = require('knex')({client: 'mysql'});
describe('NQL -> SQL', function () {
describe('Can handle regexes safely', function () {
it('can handle regex STRING with escaped quotes', function () {
let query;
query = nql(`name:~'John O\\'Nolan'`);
query.lex().should.eql([
{token: 'PROP', matched: 'name:'},
{token: 'CONTAINS', matched: '~'},
{token: 'STRING', matched: '\'John O\\\'Nolan\''}
]);
query.toJSON().should.eql({name: {$regex: /John O'Nolan/i}});
query.querySQL(knex('users')).toQuery().should.eql('select * from `users` where lower(`users`.`name`) like \'%john o\\\'nolan%\' ESCAPE \'*\'');
query = nql(`name:~'John O\\"Nolan'`);
query.toJSON().should.eql({name: {$regex: /John O"Nolan/i}});
query.lex().should.eql([
{token: 'PROP', matched: 'name:'},
{token: 'CONTAINS', matched: '~'},
{token: 'STRING', matched: '\'John O\\"Nolan\''}
]);
query.querySQL(knex('users')).toQuery().should.eql('select * from `users` where lower(`users`.`name`) like \'%john o\\"nolan%\' ESCAPE \'*\'');
query = nql(`name:~'A\\'B\\"C\\"D\\''`);
query.toJSON().should.eql({name: {$regex: /A'B"C"D'/i}});
query.lex().should.eql([
{token: 'PROP', matched: 'name:'},
{token: 'CONTAINS', matched: '~'},
{token: 'STRING', matched: '\'A\\\'B\\"C\\"D\\\'\''}
]);
query.querySQL(knex('users')).toQuery().should.eql('select * from `users` where lower(`users`.`name`) like \'%a\\\'b\\"c\\"d\\\'%\' ESCAPE \'*\'');
});
it('errors for unescaped quotes / injection patterns', function () {
(function () {
nql(`name:~'bad';'`).lex();
}).should.throw();
(function () {
nql(`name:~'';'`).lex();
}).should.throw();
let query;
// we can't force bad quotes, it errors as above
// query = nql("name:~'';select * from `settings` where `value` like ''");
// Can we trick SQL?
query = nql("name:~'\\';select * from `settings` where `value` like \\''"); // eslint-disable-line quotes
// The regex only has the regex chars escaped, not quotes
query.toJSON().should.eql({name: {$regex: /';select \* from `settings` where `value` like '/i}});
//SQL still ends up correctly escaped. This is all handled by knex... but having a test feels right
query.querySQL(knex('users')).toQuery().should.eql('select * from `users` where lower(`users`.`name`) like \'%\\\';select ** from `settings` where `value` like \\\'%\' ESCAPE \'*\'');
});
});
describe('Can combine not-equals filters into NIN correctly', function () {
it('can collapse two NE filters into a single NOT IN', function () {
let query;
query = nql('tag:-tag1+tag:-tag2');
query.toJSON().should.eql({tag: {$nin: ['tag1', 'tag2']}});
query.querySQL(knex('posts')).toQuery().should.eql('select * from `posts` where `posts`.`tag` not in (\'tag1\', \'tag2\')');
});
it('can collapse NE filters that are in nested $and statements', function () {
let query;
query = nql('(tag:-tag1+tag:-tag2)+type:post');
query.toJSON().should.eql({$and: [{tag: {$nin: ['tag1', 'tag2']}}, {type: 'post'}]});
query.querySQL(knex('posts')).toQuery().should.eql('select * from `posts` where (`posts`.`tag` not in (\'tag1\', \'tag2\') and `posts`.`type` = \'post\')');
});
it('can collapse multiple NE filters into a single NOT IN', function () {
let query;
query = nql('tag:-tag1+tag:-tag2+tag:-tag3+tag:-tag4+tag:-tag5');
query.toJSON().should.eql({tag: {$nin: ['tag1', 'tag2', 'tag3', 'tag4', 'tag5']}});
query.querySQL(knex('posts')).toQuery().should.eql('select * from `posts` where `posts`.`tag` not in (\'tag1\', \'tag2\', \'tag3\', \'tag4\', \'tag5\')');
});
it('will not collapse not equals and nequals on the same property', function () {
let query;
query = nql('tag:-tag1+tag:tag2');
query.toJSON().should.eql({$and: [{tag: {$ne: 'tag1'}}, {tag: 'tag2'}]});
query.querySQL(knex('posts')).toQuery().should.eql('select * from `posts` where (`posts`.`tag` != \'tag1\' and `posts`.`tag` = \'tag2\')');
});
});
});