Skip to content

Commit b1f7566

Browse files
committed
Force UTC timezone to make some tests (e.g. typeorm-query-service.spec) deterministic
Filter registration on module initialization Add tests at the query service level to test the e2e pipeline, with and without relations
1 parent a6a5ec3 commit b1f7566

23 files changed

+54879
-23623
lines changed

package-lock.json

Lines changed: 54656 additions & 23544 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
"lint": "eslint --cache --ext=.ts .",
1515
"lint:no-cache": "eslint --ext=.ts .",
1616
"lint:fix": "eslint --fix --ext=.ts .",
17-
"jest": "jest --runInBand --coverage",
18-
"jest:e2e": "jest --runInBand --config=./jest.e2e.config.js",
19-
"jest:unit": "jest --coverage --config=./jest.unit.config.js",
17+
"jest": "TZ=UTC jest --runInBand --coverage",
18+
"jest:e2e": "TZ=UTC jest --runInBand --config=./jest.e2e.config.js",
19+
"jest:unit": "TZ=UTC jest --coverage --config=./jest.unit.config.js",
2020
"coverage": "cat ./coverage/lcov.info | coveralls",
2121
"prepare": "husky install"
2222
},

packages/query-typeorm/__tests__/__fixtures__/custom-filters.services.ts

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,27 @@ type IsMultipleOfOpType = 'isMultipleOf';
66

77
@Injectable()
88
export class IsMultipleOfCustomFilter implements CustomFilter<IsMultipleOfOpType> {
9-
constructor() {}
10-
119
readonly operations: IsMultipleOfOpType[] = ['isMultipleOf'];
1210

1311
apply(field: string, cmp: IsMultipleOfOpType, val: unknown, alias?: string): CustomFilterResult {
1412
alias = alias ? alias : '';
1513
const pname = `param${randomString()}`;
1614
return {
17-
sql: `("${alias}"."${field}" % :${pname}) == 0`,
15+
sql: `(${alias}.${field} % :${pname}) == 0`,
1816
params: { [pname]: val },
1917
};
2018
}
2119
}
2220

2321
@Injectable()
2422
export class IsMultipleOfDateCustomFilter implements CustomFilter<IsMultipleOfOpType> {
25-
constructor() {}
26-
2723
readonly operations: IsMultipleOfOpType[] = ['isMultipleOf'];
2824

2925
apply(field: string, cmp: IsMultipleOfOpType, val: unknown, alias?: string): CustomFilterResult {
3026
alias = alias ? alias : '';
3127
const pname = `param${randomString()}`;
3228
return {
33-
sql: `(EXTRACT(EPOCH FROM "${alias}"."${field}") / 3600 / 24) % :${pname}) == 0`,
29+
sql: `(EXTRACT(EPOCH FROM ${alias}.${field}) / 3600 / 24) % :${pname}) == 0`,
3430
params: { [pname]: val },
3531
};
3632
}
@@ -40,8 +36,6 @@ type RadiusCustomFilterOp = 'distanceFrom';
4036

4137
@Injectable()
4238
export class RadiusCustomFilter implements CustomFilter<RadiusCustomFilterOp> {
43-
constructor() {}
44-
4539
readonly operations: RadiusCustomFilterOp[] = ['distanceFrom'];
4640

4741
apply(
@@ -55,7 +49,7 @@ export class RadiusCustomFilter implements CustomFilter<RadiusCustomFilterOp> {
5549
const plng = `param${randomString()}`;
5650
const prad = `param${randomString()}`;
5751
return {
58-
sql: `ST_Distance("${alias}"."${field}", ST_MakePoint(:${plat},:${plng})) <= :${prad}`,
52+
sql: `ST_Distance(${alias}.${field}, ST_MakePoint(:${plat},:${plng})) <= :${prad}`,
5953
params: { [plat]: val.point.lat, [plng]: val.point.lng, [prad]: val.radius },
6054
};
6155
}

packages/query-typeorm/__tests__/__fixtures__/seeds.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,33 @@ export const TEST_SOFT_DELETE_ENTITIES: TestSoftDeleteEntity[] = [1, 2, 3, 4, 5,
2323
};
2424
});
2525

26-
export const TEST_RELATIONS: TestRelation[] = TEST_ENTITIES.reduce(
27-
(relations, te) => [
26+
// Generate different numberTypes so we can use them for filters later on
27+
export const TEST_RELATIONS: TestRelation[] = TEST_ENTITIES.reduce((relations, te) => {
28+
return [
2829
...relations,
2930
{
3031
testRelationPk: `test-relations-${te.testEntityPk}-1`,
3132
relationName: `${te.stringType}-test-relation-one`,
3233
testEntityId: te.testEntityPk,
3334
uniDirectionalTestEntityId: te.testEntityPk,
34-
numberType: 42,
35+
numberType: te.numberType * 10 + 1,
3536
},
3637
{
3738
testRelationPk: `test-relations-${te.testEntityPk}-2`,
3839
relationName: `${te.stringType}-test-relation-two`,
3940
testEntityId: te.testEntityPk,
4041
uniDirectionalTestEntityId: te.testEntityPk,
41-
numberType: 42,
42+
numberType: te.numberType * 10 + 2,
4243
},
4344
{
4445
testRelationPk: `test-relations-${te.testEntityPk}-3`,
4546
relationName: `${te.stringType}-test-relation-three`,
4647
testEntityId: te.testEntityPk,
4748
uniDirectionalTestEntityId: te.testEntityPk,
48-
numberType: 42,
49+
numberType: te.numberType * 10 + 3,
4950
},
50-
],
51-
[] as TestRelation[],
52-
);
51+
];
52+
}, [] as TestRelation[]);
5353

5454
export const TEST_RELATIONS_OF_RELATION = TEST_RELATIONS.map<Partial<RelationOfTestRelationEntity>>((testRelation) => ({
5555
relationName: `test-relation-of-${testRelation.relationName}`,

packages/query-typeorm/__tests__/__fixtures__/test-relation.entity.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,14 @@ import { ManyToOne, Column, Entity, JoinColumn, ManyToMany, OneToOne, OneToMany,
22
import { TestEntityRelationEntity } from './test-entity-relation.entity';
33
import { TestEntity } from './test.entity';
44
import { RelationOfTestRelationEntity } from './relation-of-test-relation.entity';
5+
import { TypeormQueryFilter } from '../../src/decorators/typeorm-query-filter.decorator';
6+
import { IsMultipleOfCustomFilter } from './custom-filters.services';
57

68
@Entity()
9+
@TypeormQueryFilter<TestRelation>({
10+
filter: IsMultipleOfCustomFilter,
11+
fields: ['numberType'], // Try the scoped registration
12+
})
713
export class TestRelation {
814
@PrimaryColumn({ name: 'test_relation_pk' })
915
testRelationPk!: string;

packages/query-typeorm/__tests__/__fixtures__/test.entity.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
import { Column, Entity, OneToMany, ManyToMany, JoinTable, OneToOne, JoinColumn, PrimaryColumn } from 'typeorm';
2-
import { TypeormQueryFilter, TypeormQueryFilterOpts } from '../../src/decorators/typeorm-query-filter.decorator';
3-
import { IsMultipleOfCustomFilter } from './custom-filters.services';
2+
import { TypeormQueryFilter } from '../../src/decorators/typeorm-query-filter.decorator';
3+
import { IsMultipleOfCustomFilter, IsMultipleOfDateCustomFilter } from './custom-filters.services';
44
import { TestEntityRelationEntity } from './test-entity-relation.entity';
55
import { TestRelation } from './test-relation.entity';
66

77
@Entity()
88
@TypeormQueryFilter<TestEntity>({
99
filter: IsMultipleOfCustomFilter,
10-
} as TypeormQueryFilterOpts<TestEntity>)
10+
})
11+
@TypeormQueryFilter<TestEntity>({
12+
filter: IsMultipleOfDateCustomFilter,
13+
fields: ['dateType'],
14+
})
1115
export class TestEntity {
1216
@PrimaryColumn({ name: 'test_entity_pk' })
1317
testEntityPk!: string;

packages/query-typeorm/__tests__/module.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ describe('NestjsQueryTypeOrmModule', () => {
77
const typeOrmModule = NestjsQueryTypeOrmModule.forFeature([TestEntity]);
88
expect(typeOrmModule.imports).toHaveLength(1);
99
expect(typeOrmModule.module).toBe(NestjsQueryTypeOrmModule);
10-
expect(typeOrmModule.providers).toHaveLength(2);
10+
expect(typeOrmModule.providers).toHaveLength(3);
1111
expect(typeOrmModule.exports).toHaveLength(2);
1212
});
1313
});

packages/query-typeorm/__tests__/providers.spec.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Repository } from 'typeorm';
44
import { mock, instance } from 'ts-mockito';
55
import { createTypeOrmQueryServiceProviders } from '../src/providers';
66
import { TypeOrmQueryService } from '../src/services';
7+
import { CustomFilterRegistry } from '../src/query';
78

89
describe('createTypeOrmQueryServiceProviders', () => {
910
it('should create a provider for the entity', () => {
@@ -12,7 +13,7 @@ describe('createTypeOrmQueryServiceProviders', () => {
1213
const providers = createTypeOrmQueryServiceProviders([TestEntity]);
1314
expect(providers).toHaveLength(1);
1415
expect(providers[0].provide).toBe(getQueryServiceToken(TestEntity));
15-
expect(providers[0].inject).toEqual([getRepositoryToken(TestEntity)]);
16+
expect(providers[0].inject).toEqual([getRepositoryToken(TestEntity), CustomFilterRegistry]);
1617
expect(providers[0].useFactory(instance(mockRepo))).toBeInstanceOf(TypeOrmQueryService);
1718
});
1819
});

packages/query-typeorm/__tests__/query/__snapshots__/filter-query.builder.spec.ts.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ exports[`FilterQueryBuilder #delete with sorting should ignore sorting 1`] = `DE
1212

1313
exports[`FilterQueryBuilder #delete with sorting should ignore sorting 2`] = `Array []`;
1414

15-
exports[`FilterQueryBuilder #select with custom filter should add custom filters 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"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk" FROM "test_entity" "TestEntity" WHERE ("TestEntity"."number_type" >= ? OR "TestEntity"."number_type" <= ? OR ("TestEntity"."numberType" % ?) == 0) AND ((EXTRACT(EPOCH FROM "TestEntity"."dateType") / 3600 / 24) % ?) == 0) AND (ST_Distance("TestEntity"."fakePointType", ST_MakePoint(?,?)) <= ?)`;
15+
exports[`FilterQueryBuilder #select with custom filter should add custom filters 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"."oneTestRelationTestRelationPk" AS "TestEntity_oneTestRelationTestRelationPk" FROM "test_entity" "TestEntity" WHERE ("TestEntity"."number_type" >= ? OR "TestEntity"."number_type" <= ? OR ("TestEntity"."number_type" % ?) == 0) AND ((EXTRACT(EPOCH FROM "TestEntity"."date_type") / 3600 / 24) % ?) == 0) AND (ST_Distance(TestEntity.fakePointType, ST_MakePoint(?,?)) <= ?)`;
1616

1717
exports[`FilterQueryBuilder #select with custom filter should add custom filters 2`] = `
1818
Array [
@@ -26,7 +26,7 @@ Array [
2626
]
2727
`;
2828

29-
exports[`FilterQueryBuilder #select with custom filter should add custom filters with aggregate 1`] = `SELECT MAX("TestEntity"."number_type") AS "MAX_numberType" FROM "test_entity" "TestEntity" WHERE ("TestEntity"."number_type" >= ? OR "TestEntity"."number_type" <= ? OR ("TestEntity"."numberType" % ?) == 0) AND ((EXTRACT(EPOCH FROM "TestEntity"."dateType") / 3600 / 24) % ?) == 0) AND (ST_Distance("TestEntity"."fakePointType", ST_MakePoint(?,?)) <= ?)`;
29+
exports[`FilterQueryBuilder #select with custom filter should add custom filters with aggregate 1`] = `SELECT MAX("TestEntity"."number_type") AS "MAX_numberType" FROM "test_entity" "TestEntity" WHERE ("TestEntity"."number_type" >= ? OR "TestEntity"."number_type" <= ? OR ("TestEntity"."number_type" % ?) == 0) AND ((EXTRACT(EPOCH FROM "TestEntity"."date_type") / 3600 / 24) % ?) == 0) AND (ST_Distance(TestEntity.fakePointType, ST_MakePoint(?,?)) <= ?)`;
3030

3131
exports[`FilterQueryBuilder #select with custom filter should add custom filters with aggregate 2`] = `
3232
Array [

packages/query-typeorm/__tests__/query/__snapshots__/relation-query.builder.spec.ts.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ Array [
7272
]
7373
`;
7474

75-
exports[`RelationQueryBuilder #select with custom filters should accept custom filters 1`] = `SELECT "testEntityRelation"."test_relation_id" AS "testEntityRelation_test_relation_id", "testEntityRelation"."test_entity_id" AS "testEntityRelation_test_entity_id" FROM "test_entity_relation_entity" "testEntityRelation" WHERE ("testEntityRelation"."test_entity_id" = ?) AND (testEntityRelation.numberType >= ? OR testEntityRelation.numberType <= ? OR ("testEntityRelation"."numberType" % ?) == 0) AND ((EXTRACT(EPOCH FROM "testEntityRelation"."dateType") / 3600 / 24) % ?) == 0) AND (ST_Distance("testEntityRelation"."fakePointType", ST_MakePoint(?,?)) <= ?)`;
75+
exports[`RelationQueryBuilder #select with custom filters should accept custom filters 1`] = `SELECT "testRelations"."test_relation_pk" AS "testRelations_test_relation_pk", "testRelations"."relation_name" AS "testRelations_relation_name", "testRelations"."test_entity_id" AS "testRelations_test_entity_id", "testRelations"."uni_directional_test_entity_id" AS "testRelations_uni_directional_test_entity_id", "testRelations"."number_type" AS "testRelations_number_type", "testRelations"."uni_directional_relation_test_entity_id" AS "testRelations_uni_directional_relation_test_entity_id" FROM "test_relation" "testRelations" WHERE ("testRelations"."test_entity_id" = ?) AND ("testRelations"."number_type" >= ? OR "testRelations"."number_type" <= ? OR ("testRelations"."number_type" % ?) == 0) AND ((EXTRACT(EPOCH FROM testRelations.dateType) / 3600 / 24) % ?) == 0) AND (ST_Distance(testRelations.fakePointType, ST_MakePoint(?,?)) <= ?)`;
7676

7777
exports[`RelationQueryBuilder #select with custom filters should accept custom filters 2`] = `
7878
Array [

0 commit comments

Comments
 (0)