Skip to content

Commit

Permalink
fix(postgres): allow type casting in nested conditions
Browse files Browse the repository at this point in the history
```ts
em.find(Book, {
  author: {
    [expr('age::text')]: { $ilike: '2%' },
  },
});
```

Closes #2227
  • Loading branch information
B4nan committed Sep 23, 2021
1 parent ef9f2a3 commit bbd0eb4
Show file tree
Hide file tree
Showing 3 changed files with 10 additions and 3 deletions.
3 changes: 2 additions & 1 deletion packages/knex/src/query/CriteriaNode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export class CriteriaNode implements ICriteriaNode {
Utils.splitPrimaryKeys(key).forEach(k => {
this.prop = meta.props.find(prop => prop.name === k || (prop.fieldNames || []).includes(k));

if (validate && !this.prop && !k.includes('.') && !Utils.isOperator(k) && !CriteriaNode.isCustomExpression(k)) {
// do not validate if the key is prefixed or type casted (e.g. `k::text`)
if (validate && !this.prop && !k.includes('.') && !k.includes('::') && !Utils.isOperator(k) && !CriteriaNode.isCustomExpression(k)) {
throw new Error(`Trying to query by not existing property ${entityName}.${k}`);
}
});
Expand Down
4 changes: 3 additions & 1 deletion packages/knex/src/query/QueryBuilderHelper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -545,7 +545,9 @@ export class QueryBuilderHelper {
}

static isCustomExpression(field: string, hasAlias = false): boolean {
const re = hasAlias ? /[ ?<>=()'"`]|^\d/ : /[?<>=()'"`]|^\d/; // if we do not have alias, we don't consider spaces as custom expressions
// if we do not have alias, we don't consider spaces as custom expressions
const re = hasAlias ? /[ ?<>=()'"`:]|^\d/ : /[?<>=()'"`:]|^\d/;

return !!field.match(re);
}

Expand Down
6 changes: 5 additions & 1 deletion tests/EntityManager.postgre.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1367,6 +1367,7 @@ describe('EntityManagerPostgre', () => {

test('find with custom function', async () => {
const author = new Author2('name', 'email');
author.age = 123;
const b1 = new Book2('b1', author);
const b2 = new Book2('b2', author);
const b3 = new Book2('b3', author);
Expand All @@ -1379,9 +1380,12 @@ describe('EntityManagerPostgre', () => {

const books1 = await orm.em.find(Book2, {
[expr('upper(title)')]: ['B1', 'B2'],
author: {
[expr('age::text')]: { $ilike: '%2%' },
},
}, { populate: ['perex'] });
expect(books1).toHaveLength(2);
expect(mock.mock.calls[0][0]).toMatch(`select "e0".*, "e0".price * 1.19 as "price_taxed" from "book2" as "e0" where "e0"."author_id" is not null and upper(title) in ('B1', 'B2')`);
expect(mock.mock.calls[0][0]).toMatch(`select "e0".*, "e0".price * 1.19 as "price_taxed" from "book2" as "e0" left join "author2" as "e1" on "e0"."author_id" = "e1"."id" where "e0"."author_id" is not null and upper(title) in ('B1', 'B2') and e1.age::text ilike '%2%'`);
orm.em.clear();

const books2 = await orm.em.find(Book2, {
Expand Down

0 comments on commit bbd0eb4

Please sign in to comment.