From a8518579929676bb27ab5bf67ff8617ef19574a8 Mon Sep 17 00:00:00 2001 From: Fernando Hurtado Date: Wed, 2 Oct 2024 13:09:30 +0200 Subject: [PATCH] fix: filtering of sub-queries (#53) https://github.com/orgs/synthql/projects/1/views/1?pane=issue&itemId=81880173 --- .../queryBuilder/compareJoins.test.ts | 3 ++ .../queryBuilder/createAugmentedQuery.ts | 16 +++++----- .../executors/PgExecutor/queryBuilder/exp.ts | 32 ++++++++++++------- .../PgExecutor/queryBuilder/types.ts | 3 +- packages/backend/src/tests/e2e/select.test.ts | 16 ++++++++++ .../static/reference/assets/navigation.js | 2 +- .../docs/static/reference/assets/search.js | 2 +- 7 files changed, 51 insertions(+), 23 deletions(-) diff --git a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/compareJoins.test.ts b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/compareJoins.test.ts index dd9590fc..550f61eb 100644 --- a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/compareJoins.test.ts +++ b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/compareJoins.test.ts @@ -19,6 +19,7 @@ describe('compareJoins', () => { otherColumn: store.column('manager_id'), }, ], + where: {}, }, { table: pet, @@ -29,6 +30,7 @@ describe('compareJoins', () => { otherColumn: person.column('id'), }, ], + where: {}, }, { table: pet, @@ -39,6 +41,7 @@ describe('compareJoins', () => { otherColumn: person.column('id'), }, ], + where: {}, }, ]; diff --git a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts index 720285eb..c3beb7e4 100644 --- a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts +++ b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/createAugmentedQuery.ts @@ -63,6 +63,10 @@ function collectJoins(query: AnyQuery, defaultSchema: string): Array { }, ); + const whereExceptRefOps: Where = Object.fromEntries( + Object.entries(query.where).filter(([_, refOp]) => !isRefOp(refOp)), + ); + if (conditions.length === 0) { return []; } @@ -71,6 +75,7 @@ function collectJoins(query: AnyQuery, defaultSchema: string): Array { { table: TableRef.fromQuery(defaultSchema, query), conditions, + where: whereExceptRefOps, }, ]; }); @@ -80,12 +85,7 @@ function collectWhere( query: AnyQuery, defaultSchema: string, ): Array<{ table: TableRef; where: Where }> { - return collectFromQuery(query, (query) => { - return [ - { - table: TableRef.fromQuery(defaultSchema, query), - where: query.where, - }, - ]; - }); + return [ + { table: TableRef.fromQuery(defaultSchema, query), where: query.where }, + ]; } diff --git a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts index 9c3f73db..bc568c69 100644 --- a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts +++ b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/exp.ts @@ -358,24 +358,32 @@ export class SqlBuilder { leftJoin(join: Join) { const table = join.table; + const where = new SqlBuilder().expressionFromWhere({ + table, + where: join.where, + }); + return this.add('left join ') .add(table.canonical()) .space() .add(table.aliasQuoted()) .add(' on ') .addInterleaved( - join.conditions.map((cond) => { - const own = cond.ownColumn.aliasQuoted(); - const other = cond.otherColumn.aliasQuoted(); - const op = cond.op; - return new SqlBuilder() - .add(own) - .space() - .add(op) - .space() - .add(other) - .space(); - }), + [ + ...join.conditions.map((cond) => { + const own = cond.ownColumn.aliasQuoted(); + const other = cond.otherColumn.aliasQuoted(); + const op = cond.op; + return new SqlBuilder() + .add(own) + .space() + .add(op) + .space() + .add(other) + .space(); + }), + where, + ].filter((b) => !b.isEmpty()), SqlBuilder.and(), ); } diff --git a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/types.ts b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/types.ts index 010de7fe..03097f09 100644 --- a/packages/backend/src/execution/executors/PgExecutor/queryBuilder/types.ts +++ b/packages/backend/src/execution/executors/PgExecutor/queryBuilder/types.ts @@ -1,7 +1,7 @@ import { SqlBuilder } from './exp'; import { TableRef } from '../../../../refs/TableRef'; import { ColumnRef } from '../../../../refs/ColumnRef'; -import { JoinOp } from '@synthql/queries'; +import { AnyQuery, JoinOp, Where } from '@synthql/queries'; export interface Selection { extractFromRow(row: any, target: any): void; @@ -15,4 +15,5 @@ export type Join = { otherColumn: ColumnRef; op: JoinOp; }>; + where: AnyQuery['where']; }; diff --git a/packages/backend/src/tests/e2e/select.test.ts b/packages/backend/src/tests/e2e/select.test.ts index 6a4b0cfa..2740d4af 100644 --- a/packages/backend/src/tests/e2e/select.test.ts +++ b/packages/backend/src/tests/e2e/select.test.ts @@ -203,4 +203,20 @@ describe('select', () => { ), ).toEqual(resultNonDeferred); }); + + test('join with where', async () => { + const language = from('language') + .columns('name') + .where({ + language_id: col('film.language_id'), + name: 'Fake language', + }) + .all(); + + const query = from('film').columns('title').include({ language }).all(); + + const result = await run(query); + + expect(result.flatMap((r) => r.language)).toEqual([]); + }); }); diff --git a/packages/docs/static/reference/assets/navigation.js b/packages/docs/static/reference/assets/navigation.js index 4b21da91..c7721b38 100644 --- a/packages/docs/static/reference/assets/navigation.js +++ b/packages/docs/static/reference/assets/navigation.js @@ -1 +1 @@ -window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA5WXUU/bMBCA/0ueyxhssK1vpVQa2wRdW22aEELGuVIL10ltBzWa9t+nOGnjxM7ZvJLPn8++83G9/5to2OtknDwR+gIiPVWSJqMkJ3qTjJNtlhYc1Gnz8VFJ+m6jtzwZJS9MpMn4fJTQDeOpBJGM74+ynwXIciaemYBWRjlRqiezwK747Pzzv9HRtyyF3uz4TMpM4kKbxIzWxnOZ5aq1MqFBrgkdjtQs6N3DxWVfPudExFkrEtPRjHOg+gdRuhWuC0E1y0TXZ6Fd4+XHjnCbZwrM5mFjyzrKB1vKmb94KGeewrFWbohIOcgT2OcSlPJbGuixgaJLkUogGmb1qqY6vtYu39F92yAK9EYO5xKw1/ihKiL6RLew10MH0WXu07pLeju9//Lp7MLOibtiAbsC7AqM3qtZGdqyvmbsdG6ajrsOLUYTxISWmcqBDqSn/R6dnGcQIIkGX9A93QFFQ9wVIBkMvInmY3Rw04wXW3ENa29fsm1HEutLR6hqiCA1A38b9YrbNVFbvMGMCpd0A1sSlNUYJlqRJw4xV3kAMdlElNdX/ZdlSwwQekATUfZaulfkaeVelwk84DJMrKtzW8M6964c4xUTRJZ3OaY7MLGu6i1mTiv1GWsy5J0SmTJBONNoQiwsaDQVjsoMEedZlTma3ZaK8/0ivIgQGixkvIY1SAnpAlTBnX85trRLhrw3gvIiRaNskJDpW8YEXn81EfIEH2zUa63HSCLJFrQ7Dji6IxnlDSfBwkLGBazxazNAyLKEasrFNDUR8gRbXFR/+70BiVoMEGWZclKosKvGgp3t5nay+PN4N58tJqu7xbLVvhLJqpP1+luP7/o/dGa1jPsmHNtGM478BGFqqGb9tj6PqntFNmT0lFpHlFebhTQGQiS7oR9ZtsRAJ2foJCiBDM2p5lP0FNgMyNNMmD/45pdW2IXRyaomTZq+g9PTHOUBDFWxGgi3reFW3WX7F9qp4CaKucxeWeqvPyfkA4wW3+A9+MQOjqjVW8Q92FNbrbhQ0ESBO1suSuZkDHd6S8y8gYf/O5IR9qYSAAA=" \ No newline at end of file +window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAE5WXUU/bMBCA/0ueyxhssK1vpVQa2wRdW22aEELGuVIL10ltBzWa9t+nOGnjxM7ZvJLPn8++83G9/5to2OtknDwR+gIiPVWSJqMkJ3qTjJNtlhYc1Gnz8VFJ+m6jtzwZJS9MpMn4fJTQDeOpBJGM74+ynwXIciaemYBWRjlRqiezwK747Pzzv9HRtyyF3uz4TMpM4kKbxIzWxnOZ5aq1MqFBrgkdjtQs6N3DxWVfPudExFkrEtPRjHOg+gdRuhWuC0E1y0TXZ6Fd4+XHjnCbZwrM5mFjyzrKB1vKmb94KGeewrFWbohIOcgT2OcSlPJbGuixgaJLkUogGmb1qqY6vtYu39F92yAK9EYO5xKw1/ihKiL6RLew10MH0WXu07pLeju9//Lp7MLOibtiAbsC7AqM3qtZGdqyvmbsdG6ajrsOLUYTxISWmcqBDqSn/R6dnGcQIIkGX9A93QFFQ9wVIBkMvInmY3Rw04wXW3ENa29fsm1HEutLR6hqiCA1A38b9YrbNVFbvMGMCpd0A1sSlNUYJlqRJw4xV3kAMdlElNdX/ZdlSwwQekATUfZaulfkaeVelwk84DJMrKtzW8M6964c4xUTRJZ3OaY7MLGu6i1mTiv1GWsy5J0SmTJBONNoQiwsaDQVjsoMEedZlTma3ZaK8/0ivIgQGixkvIY1SAnpAlTBnX85trRLhrw3gvIiRaNskJDpW8YEXn81EfIEH2zUa63HSCLJFrQ7Dji6IxnlDSfBwkLGBazxazNAyLKEasrFNDUR8gRbXFR/+70BiVoMEGWZclKosKvGgp3t5nay+PN4N58tJqu7xbLVvhLJqpP1+luP7/o/dGa1jPsmHNtGM478BGFqqGb9tj6PqntFNmT0lFpHlFebhTQGQiS7oR9ZtsRAJ2foJCiBDM2p5lP0FNgMyNNMmD/45pdW2IXRyaomTZq+g9PTHOUBDFWxGgi3reFW3WX7F9qp4CaKucxeWeqvPyfkA4wW3+A9+MQOjqjVW8Q92FNbrbhQ0ESBO1suSuZkDHd6S8y8gYf/O5IR9qYSAAA=" \ No newline at end of file diff --git a/packages/docs/static/reference/assets/search.js b/packages/docs/static/reference/assets/search.js index bcbbda6a..99eabca9 100644 --- a/packages/docs/static/reference/assets/search.js +++ b/packages/docs/static/reference/assets/search.js @@ -1 +1 @@ -window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file +window.searchData = "data:application/octet-stream;base64,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"; \ No newline at end of file