From 25b892fa19e4745d4d8fa51714e592921b10357e Mon Sep 17 00:00:00 2001 From: Chad Jensen Date: Mon, 4 Dec 2023 10:15:41 -0600 Subject: [PATCH 1/6] fix: Resolve SQL Relationship Filtering In this commit, I address the issue where relations filters were not being applied. Also adding tests. --- package.json | 2 +- .../filter-query.builder.spec.ts.snap | 20 ++++++++++++++ .../query/filter-query.builder.spec.ts | 26 ++++++++++++++++++- .../src/query/filter-query.builder.ts | 13 ++++------ 4 files changed, 51 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 164080529..80dea501c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestjs-query", - "version": "4.3.2", + "version": "4.3.3", "private": true, "workspaces": [ "packages/**" diff --git a/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap b/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap index 3744c01fc..7928078ca 100644 --- a/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap +++ b/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap @@ -54,6 +54,26 @@ FROM "test_entity" "TestEntity"" `; +exports[`FilterQueryBuilder #select with paging should apply filtering on one to many relations query filter 1`] = ` +"SELECT + "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", + "TestEntity"."string_type" AS "TestEntity_string_type", + "TestEntity"."bool_type" AS "TestEntity_bool_type", + "TestEntity"."number_type" AS "TestEntity_number_type", + "TestEntity"."date_type" AS "TestEntity_date_type", + "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", + "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", + "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", + "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", + "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", + "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", + "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", + "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" +FROM + "test_entity" "TestEntity" + LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk"" +`; + exports[`FilterQueryBuilder #select with paging should apply paging args going backward 1`] = ` "SELECT "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", diff --git a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts index 734bbf25e..f69c754c0 100644 --- a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts @@ -1,7 +1,7 @@ import { Class, Filter, Query, SortDirection, SortNulls } from '@ptc-org/nestjs-query-core' import { format as formatSql } from 'sql-formatter' import { anything, deepEqual, instance, mock, verify, when } from 'ts-mockito' -import { DataSource, QueryBuilder, WhereExpressionBuilder } from 'typeorm' +import { Connection, DataSource, Driver, EntityManager, QueryBuilder, Repository, WhereExpressionBuilder } from 'typeorm' import { FilterQueryBuilder, WhereBuilder } from '../../src/query' import { createTestConnection } from '../__fixtures__/connection.fixture' @@ -230,6 +230,7 @@ describe('FilterQueryBuilder', (): void => { }) }) + describe('#select', () => { const expectSelectSQLSnapshot = (query: Query, whereBuilder: WhereBuilder): void => { const selectQueryBuilder = getEntityQueryBuilder(TestEntity, whereBuilder).select(query) @@ -303,6 +304,28 @@ describe('FilterQueryBuilder', (): void => { ) }) + it('should apply filtering on one to many relations query filter', () => { + const mockWhereBuilder = mock>(WhereBuilder) + when(mockWhereBuilder.build(anything(), anything(), anything(), anything())).thenCall((qb: WhereExpressionBuilder) => qb) + + expectSelectSQLSnapshot( + { + filter: { stringType: { eq: 'test' } }, + relations: [{ + name: 'oneTestRelation', + query: { + filter: { + numberType: { eq: 123 } + }, + }, + + }] + }, + instance(mockWhereBuilder) + ) + }) + + it('should use limit/offset when filtering on one to one relation', () => { const mockWhereBuilder = mock>(WhereBuilder) when(mockWhereBuilder.build(anything(), anything(), anything(), anything())).thenCall((qb: WhereExpressionBuilder) => qb) @@ -422,6 +445,7 @@ describe('FilterQueryBuilder', (): void => { instance(mockWhereBuilder) ) }) + }) }) diff --git a/packages/query-typeorm/src/query/filter-query.builder.ts b/packages/query-typeorm/src/query/filter-query.builder.ts index 2c92e482f..523fad3de 100644 --- a/packages/query-typeorm/src/query/filter-query.builder.ts +++ b/packages/query-typeorm/src/query/filter-query.builder.ts @@ -82,7 +82,7 @@ export class FilterQueryBuilder { readonly repo: Repository, readonly whereBuilder: WhereBuilder = new WhereBuilder(), readonly aggregateBuilder: AggregateBuilder = new AggregateBuilder(repo) - ) {} + ) { } /** * Create a `typeorm` SelectQueryBuilder with `WHERE`, `ORDER BY` and `LIMIT/OFFSET` clauses. @@ -278,17 +278,14 @@ export class FilterQueryBuilder { const relationAlias = relation.alias const relationChildren = relation.relations - // TODO:: Change to find and also apply the query for the relation const selectRelation = selectRelations && selectRelations.find(({ name }) => name === relationKey) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (selectRelation) { - return this.applyRelationJoinsRecursive( - rqb.leftJoinAndSelect(`${alias ?? rqb.alias}.${relationKey}`, relationAlias), - relationChildren, - selectRelation.query.relations, - relationAlias - ) + rqb = rqb.leftJoinAndSelect(`${alias ?? rqb.alias}.${relationKey}`, relationAlias); + // Apply filter for the current relation + rqb = this.applyFilter(rqb, selectRelation.query.filter, relationAlias); + return this.applyRelationJoinsRecursive(rqb, relationChildren, selectRelation.query.relations, relationAlias); } return this.applyRelationJoinsRecursive( From 0ec70e2b2a4a97bd02110dacfe338b9396213650 Mon Sep 17 00:00:00 2001 From: Chad Jensen Date: Tue, 5 Dec 2023 15:54:38 -0600 Subject: [PATCH 2/6] test: resolving test issues and setup --- .../relation-query.builder.spec.ts.snap | 46 +++++++++++++++++++ .../query/filter-query.builder.spec.ts | 24 +--------- .../query/relation-query.builder.spec.ts | 33 ++++++++++++- 3 files changed, 78 insertions(+), 25 deletions(-) diff --git a/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap b/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap index 6ab15cced..48c442a58 100644 --- a/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap +++ b/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap @@ -179,6 +179,52 @@ WHERE ("test_entity"."test_entity_pk" = test-entity-id-1)" `; +exports[`RelationQueryBuilder #select with filter should apply filtering from relations query filter 1`] = ` +"SELECT + "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", + "TestEntity"."string_type" AS "TestEntity_string_type", + "TestEntity"."bool_type" AS "TestEntity_bool_type", + "TestEntity"."number_type" AS "TestEntity_number_type", + "TestEntity"."date_type" AS "TestEntity_date_type", + "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", + "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", + "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", + "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", + "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", + "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", + "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", + "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" +FROM + "test_entity" "TestEntity" + LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk" +WHERE + (oneTestRelation.numberType = 123) + AND ("TestEntity"."string_type" = test)" +`; + +exports[`RelationQueryBuilder #select with filter should apply filtering on one to many relations and use relations query filter 1`] = ` +"SELECT + "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", + "TestEntity"."string_type" AS "TestEntity_string_type", + "TestEntity"."bool_type" AS "TestEntity_bool_type", + "TestEntity"."number_type" AS "TestEntity_number_type", + "TestEntity"."date_type" AS "TestEntity_date_type", + "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", + "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", + "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", + "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", + "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", + "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", + "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", + "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" +FROM + "test_entity" "TestEntity" + LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk" +WHERE + (oneTestRelation.numberType = 123) + AND ("TestEntity"."string_type" = test)" +`; + exports[`RelationQueryBuilder #select with filter should call whereBuilder#build if there is a filter 1`] = ` "SELECT "testRelations"."test_relation_pk" AS "testRelations_test_relation_pk", diff --git a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts index f69c754c0..a2d82c102 100644 --- a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts @@ -1,7 +1,7 @@ import { Class, Filter, Query, SortDirection, SortNulls } from '@ptc-org/nestjs-query-core' import { format as formatSql } from 'sql-formatter' import { anything, deepEqual, instance, mock, verify, when } from 'ts-mockito' -import { Connection, DataSource, Driver, EntityManager, QueryBuilder, Repository, WhereExpressionBuilder } from 'typeorm' +import { DataSource, QueryBuilder, WhereExpressionBuilder } from 'typeorm' import { FilterQueryBuilder, WhereBuilder } from '../../src/query' import { createTestConnection } from '../__fixtures__/connection.fixture' @@ -304,28 +304,6 @@ describe('FilterQueryBuilder', (): void => { ) }) - it('should apply filtering on one to many relations query filter', () => { - const mockWhereBuilder = mock>(WhereBuilder) - when(mockWhereBuilder.build(anything(), anything(), anything(), anything())).thenCall((qb: WhereExpressionBuilder) => qb) - - expectSelectSQLSnapshot( - { - filter: { stringType: { eq: 'test' } }, - relations: [{ - name: 'oneTestRelation', - query: { - filter: { - numberType: { eq: 123 } - }, - }, - - }] - }, - instance(mockWhereBuilder) - ) - }) - - it('should use limit/offset when filtering on one to one relation', () => { const mockWhereBuilder = mock>(WhereBuilder) when(mockWhereBuilder.build(anything(), anything(), anything(), anything())).thenCall((qb: WhereExpressionBuilder) => qb) diff --git a/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts index 1069fa67a..338d5071f 100644 --- a/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts @@ -1,8 +1,8 @@ import { Class, Query, SortDirection, SortNulls } from '@ptc-org/nestjs-query-core' import { format as formatSql } from 'sql-formatter' -import { DataSource } from 'typeorm' +import { DataSource, Filter } from 'typeorm' -import { RelationQueryBuilder } from '../../src/query' +import { FilterQueryBuilder, RelationQueryBuilder } from '../../src/query' import { createTestConnection } from '../__fixtures__/connection.fixture' import { TEST_ENTITIES } from '../__fixtures__/seeds' import { TestEntity } from '../__fixtures__/test.entity' @@ -20,6 +20,11 @@ describe('RelationQueryBuilder', (): void => { relationName: string ): RelationQueryBuilder => new RelationQueryBuilder(dataSource.getRepository(EntityClass), relationName) + const geFilterQueryBuilder = ( + EntityClass: Class, + ): FilterQueryBuilder => new FilterQueryBuilder(dataSource.getRepository(EntityClass)) + + const expectSQLSnapshot = ( EntityClass: Class, entity: Entity, @@ -32,6 +37,16 @@ describe('RelationQueryBuilder', (): void => { expect(formatSql(sql, { params })).toMatchSnapshot() } + const expectSQLSnapshotUsingQuery = ( + EntityClass: Class, + query: Query + ): void => { + const selectQueryBuilder = geFilterQueryBuilder(EntityClass).select(query) + const [sql, params] = selectQueryBuilder.getQueryAndParameters() + expect(formatSql(sql, { params })).toMatchSnapshot() + } + + const expectBatchSQLSnapshot = ( EntityClass: Class, entities: Entity[], @@ -121,6 +136,20 @@ describe('RelationQueryBuilder', (): void => { const query: Query = { filter: { relationName: { eq: 'foo' } } } expectSQLSnapshot(TestEntity, testEntity, 'testRelations', query) }) + it('should apply filtering from relations query filter', () => { + expectSQLSnapshotUsingQuery(TestEntity, { + filter: { stringType: { eq: 'test' } }, // note that this is the 'normal' filter. + relations: [{ + name: 'oneTestRelation', + query: { + // and this filter gets applied to the query as well. + filter: { + numberType: { eq: 123 } + }, + }, + }] + } as any) + }) }) describe('with paging', () => { From 2d9d90398773737730ba1f5287b8b73edad5eb3c Mon Sep 17 00:00:00 2001 From: Chad Jensen Date: Tue, 5 Dec 2023 15:55:56 -0600 Subject: [PATCH 3/6] test: removing unneeded snapshot --- .../filter-query.builder.spec.ts.snap | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap b/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap index 7928078ca..3744c01fc 100644 --- a/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap +++ b/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap @@ -54,26 +54,6 @@ FROM "test_entity" "TestEntity"" `; -exports[`FilterQueryBuilder #select with paging should apply filtering on one to many relations query filter 1`] = ` -"SELECT - "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", - "TestEntity"."string_type" AS "TestEntity_string_type", - "TestEntity"."bool_type" AS "TestEntity_bool_type", - "TestEntity"."number_type" AS "TestEntity_number_type", - "TestEntity"."date_type" AS "TestEntity_date_type", - "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", - "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", - "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", - "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", - "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", - "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", - "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", - "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" -FROM - "test_entity" "TestEntity" - LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk"" -`; - exports[`FilterQueryBuilder #select with paging should apply paging args going backward 1`] = ` "SELECT "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", From 3914b46d73bee1237d98a2078657d7bcabcfbda9 Mon Sep 17 00:00:00 2001 From: Chad Jensen Date: Tue, 5 Dec 2023 16:01:35 -0600 Subject: [PATCH 4/6] chore: unbumping version number --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 80dea501c..95c8252b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestjs-query", - "version": "4.3.3", + "version": "4.3.2", "private": true, "workspaces": [ "packages/**" @@ -115,4 +115,4 @@ "typescript": "5.2.2" }, "packageManager": "yarn@3.2.1" -} +} \ No newline at end of file From 0eff5c793d268f08a0c607835781bfe143426030 Mon Sep 17 00:00:00 2001 From: Chad Jensen Date: Tue, 5 Dec 2023 16:07:28 -0600 Subject: [PATCH 5/6] style: formatting/lint --- .../query/filter-query.builder.spec.ts | 2 -- .../query/relation-query.builder.spec.ts | 34 ++++++++----------- .../src/query/filter-query.builder.ts | 8 ++--- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts index a2d82c102..734bbf25e 100644 --- a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts @@ -230,7 +230,6 @@ describe('FilterQueryBuilder', (): void => { }) }) - describe('#select', () => { const expectSelectSQLSnapshot = (query: Query, whereBuilder: WhereBuilder): void => { const selectQueryBuilder = getEntityQueryBuilder(TestEntity, whereBuilder).select(query) @@ -423,7 +422,6 @@ describe('FilterQueryBuilder', (): void => { instance(mockWhereBuilder) ) }) - }) }) diff --git a/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts index 338d5071f..faa7b2cbe 100644 --- a/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts @@ -1,6 +1,6 @@ import { Class, Query, SortDirection, SortNulls } from '@ptc-org/nestjs-query-core' import { format as formatSql } from 'sql-formatter' -import { DataSource, Filter } from 'typeorm' +import { DataSource } from 'typeorm' import { FilterQueryBuilder, RelationQueryBuilder } from '../../src/query' import { createTestConnection } from '../__fixtures__/connection.fixture' @@ -20,10 +20,8 @@ describe('RelationQueryBuilder', (): void => { relationName: string ): RelationQueryBuilder => new RelationQueryBuilder(dataSource.getRepository(EntityClass), relationName) - const geFilterQueryBuilder = ( - EntityClass: Class, - ): FilterQueryBuilder => new FilterQueryBuilder(dataSource.getRepository(EntityClass)) - + const geFilterQueryBuilder = (EntityClass: Class): FilterQueryBuilder => + new FilterQueryBuilder(dataSource.getRepository(EntityClass)) const expectSQLSnapshot = ( EntityClass: Class, @@ -37,16 +35,12 @@ describe('RelationQueryBuilder', (): void => { expect(formatSql(sql, { params })).toMatchSnapshot() } - const expectSQLSnapshotUsingQuery = ( - EntityClass: Class, - query: Query - ): void => { + const expectSQLSnapshotUsingQuery = (EntityClass: Class, query: Query): void => { const selectQueryBuilder = geFilterQueryBuilder(EntityClass).select(query) const [sql, params] = selectQueryBuilder.getQueryAndParameters() expect(formatSql(sql, { params })).toMatchSnapshot() } - const expectBatchSQLSnapshot = ( EntityClass: Class, entities: Entity[], @@ -139,15 +133,17 @@ describe('RelationQueryBuilder', (): void => { it('should apply filtering from relations query filter', () => { expectSQLSnapshotUsingQuery(TestEntity, { filter: { stringType: { eq: 'test' } }, // note that this is the 'normal' filter. - relations: [{ - name: 'oneTestRelation', - query: { - // and this filter gets applied to the query as well. - filter: { - numberType: { eq: 123 } - }, - }, - }] + relations: [ + { + name: 'oneTestRelation', + query: { + // and this filter gets applied to the query as well. + filter: { + numberType: { eq: 123 } + } + } + } + ] } as any) }) }) diff --git a/packages/query-typeorm/src/query/filter-query.builder.ts b/packages/query-typeorm/src/query/filter-query.builder.ts index 523fad3de..a740c47b6 100644 --- a/packages/query-typeorm/src/query/filter-query.builder.ts +++ b/packages/query-typeorm/src/query/filter-query.builder.ts @@ -82,7 +82,7 @@ export class FilterQueryBuilder { readonly repo: Repository, readonly whereBuilder: WhereBuilder = new WhereBuilder(), readonly aggregateBuilder: AggregateBuilder = new AggregateBuilder(repo) - ) { } + ) {} /** * Create a `typeorm` SelectQueryBuilder with `WHERE`, `ORDER BY` and `LIMIT/OFFSET` clauses. @@ -282,10 +282,10 @@ export class FilterQueryBuilder { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion if (selectRelation) { - rqb = rqb.leftJoinAndSelect(`${alias ?? rqb.alias}.${relationKey}`, relationAlias); + rqb = rqb.leftJoinAndSelect(`${alias ?? rqb.alias}.${relationKey}`, relationAlias) // Apply filter for the current relation - rqb = this.applyFilter(rqb, selectRelation.query.filter, relationAlias); - return this.applyRelationJoinsRecursive(rqb, relationChildren, selectRelation.query.relations, relationAlias); + rqb = this.applyFilter(rqb, selectRelation.query.filter, relationAlias) + return this.applyRelationJoinsRecursive(rqb, relationChildren, selectRelation.query.relations, relationAlias) } return this.applyRelationJoinsRecursive( From 55fa1651e77b499cb045ca0a8333e136f7ddc157 Mon Sep 17 00:00:00 2001 From: Chad Jensen Date: Wed, 6 Dec 2023 09:47:40 -0600 Subject: [PATCH 6/6] test: moving test case to other file --- .../filter-query.builder.spec.ts.snap | 23 ++++++++++ .../relation-query.builder.spec.ts.snap | 46 ------------------- .../query/filter-query.builder.spec.ts | 26 +++++++++++ .../query/relation-query.builder.spec.ts | 27 +---------- 4 files changed, 50 insertions(+), 72 deletions(-) diff --git a/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap b/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap index 3744c01fc..cb22f1d29 100644 --- a/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap +++ b/packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap @@ -10,6 +10,29 @@ exports[`FilterQueryBuilder #delete with paging should ignore paging args 1`] = exports[`FilterQueryBuilder #delete with sorting should ignore sorting 1`] = `"DELETE FROM "test_entity""`; +exports[`FilterQueryBuilder #select with filter should apply filtering from relations query filter 1`] = ` +"SELECT + "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", + "TestEntity"."string_type" AS "TestEntity_string_type", + "TestEntity"."bool_type" AS "TestEntity_bool_type", + "TestEntity"."number_type" AS "TestEntity_number_type", + "TestEntity"."date_type" AS "TestEntity_date_type", + "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", + "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", + "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", + "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", + "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", + "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", + "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", + "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" +FROM + "test_entity" "TestEntity" + LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk" +WHERE + (oneTestRelation.numberType = 123) + AND ("TestEntity"."string_type" = test)" +`; + exports[`FilterQueryBuilder #select with filter should call whereBuilder#build if there is a filter 1`] = ` "SELECT "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", diff --git a/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap b/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap index 48c442a58..6ab15cced 100644 --- a/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap +++ b/packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap @@ -179,52 +179,6 @@ WHERE ("test_entity"."test_entity_pk" = test-entity-id-1)" `; -exports[`RelationQueryBuilder #select with filter should apply filtering from relations query filter 1`] = ` -"SELECT - "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", - "TestEntity"."string_type" AS "TestEntity_string_type", - "TestEntity"."bool_type" AS "TestEntity_bool_type", - "TestEntity"."number_type" AS "TestEntity_number_type", - "TestEntity"."date_type" AS "TestEntity_date_type", - "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", - "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", - "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", - "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", - "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", - "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", - "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", - "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" -FROM - "test_entity" "TestEntity" - LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk" -WHERE - (oneTestRelation.numberType = 123) - AND ("TestEntity"."string_type" = test)" -`; - -exports[`RelationQueryBuilder #select with filter should apply filtering on one to many relations and use relations query filter 1`] = ` -"SELECT - "TestEntity"."test_entity_pk" AS "TestEntity_test_entity_pk", - "TestEntity"."string_type" AS "TestEntity_string_type", - "TestEntity"."bool_type" AS "TestEntity_bool_type", - "TestEntity"."number_type" AS "TestEntity_number_type", - "TestEntity"."date_type" AS "TestEntity_date_type", - "TestEntity"."many_to_one_relation_id" AS "TestEntity_many_to_one_relation_id", - "TestEntity"."many_to_one_soft_delete_relation_id" AS "TestEntity_many_to_one_soft_delete_relation_id", - "TestEntity"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk", - "oneTestRelation"."test_relation_pk" AS "oneTestRelation_test_relation_pk", - "oneTestRelation"."relation_name" AS "oneTestRelation_relation_name", - "oneTestRelation"."test_entity_id" AS "oneTestRelation_test_entity_id", - "oneTestRelation"."uni_directional_test_entity_id" AS "oneTestRelation_uni_directional_test_entity_id", - "oneTestRelation"."uni_directional_relation_test_entity_id" AS "oneTestRelation_uni_directional_relation_test_entity_id" -FROM - "test_entity" "TestEntity" - LEFT JOIN "test_relation" "oneTestRelation" ON "oneTestRelation"."test_relation_pk" = "TestEntity"."oneTestRelationTestRelationPk" -WHERE - (oneTestRelation.numberType = 123) - AND ("TestEntity"."string_type" = test)" -`; - exports[`RelationQueryBuilder #select with filter should call whereBuilder#build if there is a filter 1`] = ` "SELECT "testRelations"."test_relation_pk" AS "testRelations_test_relation_pk", diff --git a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts index 734bbf25e..f894271c3 100644 --- a/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/filter-query.builder.spec.ts @@ -252,6 +252,32 @@ describe('FilterQueryBuilder', (): void => { ) expectSelectSQLSnapshot(query, instance(mockWhereBuilder)) }) + + it('should apply filtering from relations query filter', () => { + const expectSQLSnapshotUsingQuery = (EntityClass: Class, query: Query): void => { + const geFilterQueryBuilder = (e: Class): FilterQueryBuilder => + new FilterQueryBuilder(connection.getRepository(e)) + + const selectQueryBuilder = geFilterQueryBuilder(EntityClass).select(query) + const [sql, params] = selectQueryBuilder.getQueryAndParameters() + expect(formatSql(sql, { params })).toMatchSnapshot() + } + + expectSQLSnapshotUsingQuery(TestEntity, { + filter: { stringType: { eq: 'test' } }, // note that this is the 'normal' filter. + relations: [ + { + name: 'oneTestRelation', + query: { + // and this filter gets applied to the query as well. + filter: { + numberType: { eq: 123 } + } + } + } + ] + } as any) + }) }) describe('with paging', () => { diff --git a/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts b/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts index faa7b2cbe..1069fa67a 100644 --- a/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts +++ b/packages/query-typeorm/__tests__/query/relation-query.builder.spec.ts @@ -2,7 +2,7 @@ import { Class, Query, SortDirection, SortNulls } from '@ptc-org/nestjs-query-co import { format as formatSql } from 'sql-formatter' import { DataSource } from 'typeorm' -import { FilterQueryBuilder, RelationQueryBuilder } from '../../src/query' +import { RelationQueryBuilder } from '../../src/query' import { createTestConnection } from '../__fixtures__/connection.fixture' import { TEST_ENTITIES } from '../__fixtures__/seeds' import { TestEntity } from '../__fixtures__/test.entity' @@ -20,9 +20,6 @@ describe('RelationQueryBuilder', (): void => { relationName: string ): RelationQueryBuilder => new RelationQueryBuilder(dataSource.getRepository(EntityClass), relationName) - const geFilterQueryBuilder = (EntityClass: Class): FilterQueryBuilder => - new FilterQueryBuilder(dataSource.getRepository(EntityClass)) - const expectSQLSnapshot = ( EntityClass: Class, entity: Entity, @@ -35,12 +32,6 @@ describe('RelationQueryBuilder', (): void => { expect(formatSql(sql, { params })).toMatchSnapshot() } - const expectSQLSnapshotUsingQuery = (EntityClass: Class, query: Query): void => { - const selectQueryBuilder = geFilterQueryBuilder(EntityClass).select(query) - const [sql, params] = selectQueryBuilder.getQueryAndParameters() - expect(formatSql(sql, { params })).toMatchSnapshot() - } - const expectBatchSQLSnapshot = ( EntityClass: Class, entities: Entity[], @@ -130,22 +121,6 @@ describe('RelationQueryBuilder', (): void => { const query: Query = { filter: { relationName: { eq: 'foo' } } } expectSQLSnapshot(TestEntity, testEntity, 'testRelations', query) }) - it('should apply filtering from relations query filter', () => { - expectSQLSnapshotUsingQuery(TestEntity, { - filter: { stringType: { eq: 'test' } }, // note that this is the 'normal' filter. - relations: [ - { - name: 'oneTestRelation', - query: { - // and this filter gets applied to the query as well. - filter: { - numberType: { eq: 123 } - } - } - } - ] - } as any) - }) }) describe('with paging', () => {