diff --git a/packages/mongo-knex/lib/convertor.js b/packages/mongo-knex/lib/convertor.js index 86555d24..fa263631 100644 --- a/packages/mongo-knex/lib/convertor.js +++ b/packages/mongo-knex/lib/convertor.js @@ -317,7 +317,25 @@ class MongoToKnex { statementValue = !_.isArray(statement.value) ? [statement.value] : statement.value; } - innerQB[statement.whereType](statementColumn, statementOp, statementValue); + if ([compOps.$regex, compOps.$not].indexOf(statementOp) === -1) { + innerQB[statement.whereType](statementColumn, statementOp, statementValue); + } else { + // knex ILike won't work because of `COLLATION 'utf8_bin'` + // e.g. COLLATION 'utf8_bin' is not valid for CHARACTER SET 'latin1' + // for MySQL, case-sensitive LIKEs won't work without casting to BINARY + // the behavior aligns with commit 7b8798a6fa7870c98648cae5a494eb761638a208 + // for an actual database agnostic solution, we need to rework everything around this + + let whereType = statement.whereType; + const {source, ignoreCase} = processRegExp(statementValue); + if (!ignoreCase) { + innerQB[whereType](statementColumn, statementOp, source); + } else { + whereType += 'Raw'; + debug(`(buildComparison) whereType: ${whereType}, statement: ${statement}, op: ${statement.operator}, comp: ${statementOp}, value: ${source} (REGEX/i)`); + innerQB[whereType](`lower(??) ${statementOp} ?`, [statementColumn, source]); + } + } }); if (debugExtended.enabled) { diff --git a/packages/mongo-knex/test/unit/convertor.test.js b/packages/mongo-knex/test/unit/convertor.test.js index 856e90b5..04859115 100644 --- a/packages/mongo-knex/test/unit/convertor.test.js +++ b/packages/mongo-knex/test/unit/convertor.test.js @@ -334,6 +334,22 @@ describe('Relations', function () { .should.eql('select * from `posts` where `posts`.`id` not in (select `posts_tags`.`post_id` from `posts_tags` inner join `tags` on `tags`.`id` = `posts_tags`.`tag_id` where `tags`.`slug` in (\'fred\'))'); }); + it('should be able to perform a regexp query on a many-to-many relation', function () { + runQuery({'tags.slug': {$regex: /foo/}}) + .should.eql('select * from `posts` where `posts`.`id` in (select `posts_tags`.`post_id` from `posts_tags` inner join `tags` on `tags`.`id` = `posts_tags`.`tag_id` where `tags`.`slug` like \'%foo%\')'); + + runQuery({'tags.slug': {$regex: /foo/i}}) + .should.eql('select * from `posts` where `posts`.`id` in (select `posts_tags`.`post_id` from `posts_tags` inner join `tags` on `tags`.`id` = `posts_tags`.`tag_id` where lower(`tags`.`slug`) like \'%foo%\')'); + }); + + it('should be able to perform a negate regexp query on a many-to-many relation', function () { + runQuery({'tags.slug': {$not: /bar/}}) + .should.eql('select * from `posts` where `posts`.`id` in (select `posts_tags`.`post_id` from `posts_tags` inner join `tags` on `tags`.`id` = `posts_tags`.`tag_id` where `tags`.`slug` not like \'%bar%\')'); + + runQuery({'tags.slug': {$not: /bar/i}}) + .should.eql('select * from `posts` where `posts`.`id` in (select `posts_tags`.`post_id` from `posts_tags` inner join `tags` on `tags`.`id` = `posts_tags`.`tag_id` where lower(`tags`.`slug`) not like \'%bar%\')'); + }); + // This case doesn't work it.skip('should be able to perform a query on a many-to-many join table alone', function () { runQuery({'posts_tags.sort_order': 0}); @@ -366,6 +382,9 @@ describe('Relations', function () { describe('RegExp/Like queries', function () { it('are well behaved', function () { + runQuery({title: {$regex: /bar/}}) + .should.eql('select * from `posts` where `posts`.`title` like \'%bar%\''); + runQuery({title: {$regex: /'/i}}) .should.eql('select * from `posts` where lower(`posts`.`title`) like \'%\\\'%\'');