Skip to content

Commit 23f5029

Browse files
authored
Merge pull request #504 from nestjsx/fix/relations
fix(typeorm): updated joining relations and column identifier
2 parents 7ef9744 + ad8d5f2 commit 23f5029

15 files changed

+420
-253
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ before_install:
1313
- sudo mv docker-compose /usr/local/bin
1414

1515
install:
16+
- docker-compose up -d
1617
- docker-compose up -d
1718
- yarn bootstrap
1819
- yarn clean

docker-compose.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,16 @@ services:
1616
networks:
1717
- nestjsx_crud
1818

19+
mysql:
20+
image: mysql:5.7
21+
ports:
22+
- 3316:3306
23+
environment:
24+
MYSQL_DATABASE: nestjsx_crud
25+
MYSQL_USER: nestjsx_crud
26+
MYSQL_PASSWORD: nestjsx_crud
27+
MYSQL_ROOT_PASSWORD: nestjsx_crud
28+
1929
redis:
2030
image: redis:alpine
2131
ports:

integration/crud-typeorm/companies/companies.controller.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,27 @@ import { serialize } from './response';
1919
},
2020
},
2121
query: {
22-
alwaysPaginate: true,
22+
alwaysPaginate: false,
23+
allow: ['name'],
2324
join: {
24-
users: {},
25-
projects: {},
25+
users: {
26+
alias: 'companyUsers',
27+
exclude: ['email'],
28+
eager: true,
29+
},
30+
'users.projects': {
31+
eager: true,
32+
alias: 'usersProjects',
33+
allow: ['name'],
34+
},
35+
'users.projects.company': {
36+
eager: true,
37+
alias: 'usersProjectsCompany',
38+
},
39+
projects: {
40+
eager: true,
41+
select: false,
42+
},
2643
},
2744
},
2845
})

integration/crud-typeorm/companies/companies.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Injectable } from '@nestjs/common';
22
import { InjectRepository } from '@nestjs/typeorm';
3-
import { TypeOrmCrudService } from '@nestjsx/crud-typeorm';
3+
import { TypeOrmCrudService } from '../../../packages/crud-typeorm/src/typeorm-crud.service';
44

55
import { Company } from './company.entity';
66

integration/crud-typeorm/orm.config.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { join } from 'path';
22
import { TypeOrmModuleOptions } from '@nestjs/typeorm';
33
import { isNil } from '@nestjsx/util';
44

5+
const type = (process.env.TYPEORM_CONNECTION as any) || 'postgres';
6+
57
export const withCache: TypeOrmModuleOptions = {
6-
type: 'postgres',
8+
type,
79
host: '127.0.0.1',
8-
port: 5455,
9-
username: 'root',
10-
password: 'root',
10+
port: type === 'postgres' ? 5455 : 3316,
11+
username: type === 'mysql' ? 'nestjsx_crud' : 'root',
12+
password: type === 'mysql' ? 'nestjsx_crud' : 'root',
1113
database: 'nestjsx_crud',
1214
synchronize: false,
1315
logging: !isNil(process.env.TYPEORM_LOGGING)

integration/crud-typeorm/orm.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,15 @@ default:
1010
migrationsTableName: orm_migrations
1111
migrations:
1212
- ./seeds.ts
13+
mysql:
14+
type: mysql
15+
host: 127.0.0.1
16+
port: 3316
17+
username: nestjsx_crud
18+
password: nestjsx_crud
19+
database: nestjsx_crud
20+
entities:
21+
- ./**/*.entity.ts
22+
migrationsTableName: orm_migrations
23+
migrations:
24+
- ./seeds.ts

integration/crud-typeorm/seeds.ts

Lines changed: 125 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,125 +1,144 @@
1-
import { MigrationInterface, QueryRunner } from 'typeorm';
1+
import { plainToClass } from 'class-transformer';
2+
import { MigrationInterface, Repository, QueryRunner } from 'typeorm';
3+
import { Company } from './companies';
4+
import { Project, UserProject } from './projects';
5+
import { Name, User } from './users';
6+
import { License, UserLicense } from './users-licenses';
7+
import { UserProfile } from './users-profiles';
28

39
export class Seeds1544303473346 implements MigrationInterface {
10+
private save<T>(repo: Repository<T>, type: any, data: Partial<T>[]): Promise<T[]> {
11+
return repo.save(
12+
data.map((partial: Partial<T>) =>
13+
plainToClass<any, any>(type, partial, { ignoreDecorators: true }),
14+
),
15+
);
16+
}
17+
418
public async up(queryRunner: QueryRunner): Promise<any> {
19+
const { connection } = queryRunner;
20+
21+
const companiesRepo = connection.getRepository(Company);
22+
const projectsRepo = connection.getRepository(Project);
23+
const usersProfilesRepo = connection.getRepository(UserProfile);
24+
const usersRepo = connection.getRepository(User);
25+
const licensesRepo = connection.getRepository(License);
26+
const usersLincesesRepo = connection.getRepository(UserLicense);
27+
const usersProjectsRepo = connection.getRepository(UserProject);
28+
529
// companies
6-
await queryRunner.query(`
7-
INSERT INTO public.companies ("name", "domain") VALUES
8-
('Name1', 'Domain1'),
9-
('Name2', 'Domain2'),
10-
('Name3', 'Domain3'),
11-
('Name4', 'Domain4'),
12-
('Name5', 'Domain5'),
13-
('Name6', 'Domain6'),
14-
('Name7', 'Domain7'),
15-
('Name8', 'Domain8'),
16-
('Name9', 'Domain9'),
17-
('Name10', 'Domain10');
18-
`);
30+
await this.save(companiesRepo, Company, [
31+
{ name: 'Name1', domain: 'Domain1' },
32+
{ name: 'Name2', domain: 'Domain2' },
33+
{ name: 'Name3', domain: 'Domain3' },
34+
{ name: 'Name4', domain: 'Domain4' },
35+
{ name: 'Name5', domain: 'Domain5' },
36+
{ name: 'Name6', domain: 'Domain6' },
37+
{ name: 'Name7', domain: 'Domain7' },
38+
{ name: 'Name8', domain: 'Domain8' },
39+
{ name: 'Name9', domain: 'Domain9' },
40+
{ name: 'Name10', domain: 'Domain10' },
41+
]);
1942

2043
// projects
21-
await queryRunner.query(`
22-
INSERT INTO public.projects ("name", "description", "isActive", "companyId") VALUES
23-
('Project1', 'description1', true, 1),
24-
('Project2', 'description2', true, 1),
25-
('Project3', 'description3', true, 2),
26-
('Project4', 'description4', true, 2),
27-
('Project5', 'description5', true, 3),
28-
('Project6', 'description6', true, 3),
29-
('Project7', 'description7', true, 4),
30-
('Project8', 'description8', true, 4),
31-
('Project9', 'description9', true, 5),
32-
('Project10', 'description10', true, 5),
33-
('Project11', 'description11', false, 6),
34-
('Project12', 'description12', false, 6),
35-
('Project13', 'description13', false, 7),
36-
('Project14', 'description14', false, 7),
37-
('Project15', 'description15', false, 8),
38-
('Project16', 'description16', false, 8),
39-
('Project17', 'description17', false, 9),
40-
('Project18', 'description18', false, 9),
41-
('Project19', 'description19', false, 10),
42-
('Project20', 'description20', false, 10);
43-
`);
44+
await this.save(projectsRepo, Project, [
45+
{ name: 'Project1', description: 'description1', isActive: true, companyId: 1 },
46+
{ name: 'Project2', description: 'description2', isActive: true, companyId: 1 },
47+
{ name: 'Project3', description: 'description3', isActive: true, companyId: 2 },
48+
{ name: 'Project4', description: 'description4', isActive: true, companyId: 2 },
49+
{ name: 'Project5', description: 'description5', isActive: true, companyId: 3 },
50+
{ name: 'Project6', description: 'description6', isActive: true, companyId: 3 },
51+
{ name: 'Project7', description: 'description7', isActive: true, companyId: 4 },
52+
{ name: 'Project8', description: 'description8', isActive: true, companyId: 4 },
53+
{ name: 'Project9', description: 'description9', isActive: true, companyId: 5 },
54+
{ name: 'Project10', description: 'description10', isActive: true, companyId: 5 },
55+
{ name: 'Project11', description: 'description11', isActive: false, companyId: 6 },
56+
{ name: 'Project12', description: 'description12', isActive: false, companyId: 6 },
57+
{ name: 'Project13', description: 'description13', isActive: false, companyId: 7 },
58+
{ name: 'Project14', description: 'description14', isActive: false, companyId: 7 },
59+
{ name: 'Project15', description: 'description15', isActive: false, companyId: 8 },
60+
{ name: 'Project16', description: 'description16', isActive: false, companyId: 8 },
61+
{ name: 'Project17', description: 'description17', isActive: false, companyId: 9 },
62+
{ name: 'Project18', description: 'description18', isActive: false, companyId: 9 },
63+
{ name: 'Project19', description: 'description19', isActive: false, companyId: 10 },
64+
{ name: 'Project20', description: 'description20', isActive: false, companyId: 10 },
65+
]);
4466

4567
// user-profiles
46-
await queryRunner.query(`
47-
INSERT INTO public.user_profiles ("name") VALUES
48-
('User1'),
49-
('User2'),
50-
('User3'),
51-
('User4'),
52-
('User5'),
53-
('User6'),
54-
('User7'),
55-
('User8'),
56-
('User9'),
57-
('User1'),
58-
('User1'),
59-
('User1'),
60-
('User1'),
61-
('User1'),
62-
('User1'),
63-
('User1'),
64-
('User1'),
65-
('User1'),
66-
('User1'),
67-
('User2');
68-
`);
68+
await this.save(usersProfilesRepo, UserProfile, [
69+
{ name: 'User1' },
70+
{ name: 'User2' },
71+
{ name: 'User3' },
72+
{ name: 'User4' },
73+
{ name: 'User5' },
74+
{ name: 'User6' },
75+
{ name: 'User7' },
76+
{ name: 'User8' },
77+
{ name: 'User9' },
78+
{ name: 'User1' },
79+
{ name: 'User1' },
80+
{ name: 'User1' },
81+
{ name: 'User1' },
82+
{ name: 'User1' },
83+
{ name: 'User1' },
84+
{ name: 'User1' },
85+
{ name: 'User1' },
86+
{ name: 'User1' },
87+
{ name: 'User1' },
88+
{ name: 'User2' },
89+
]);
6990

7091
// users
71-
await queryRunner.query(`
72-
INSERT INTO public.users ("email", "isActive", "companyId", "profileId", "nameFirst", "nameLast") VALUES
73-
('[email protected]', true, 1, 1, 'firstname1', 'lastname1'),
74-
('[email protected]', true, 1, 2, NULL, NULL),
75-
('[email protected]', true, 1, 3, NULL, NULL),
76-
('[email protected]', true, 1, 4, NULL, NULL),
77-
('[email protected]', true, 1, 5, NULL, NULL),
78-
('[email protected]', true, 1, 6, NULL, NULL),
79-
('[email protected]', false, 1, 7, NULL, NULL),
80-
('[email protected]', false, 1, 8, NULL, NULL),
81-
('[email protected]', false, 1, 9, NULL, NULL),
82-
('[email protected]', true, 1, 10, NULL, NULL),
83-
('[email protected]', true, 2, 11, NULL, NULL),
84-
('[email protected]', true, 2, 12, NULL, NULL),
85-
('[email protected]', true, 2, 13, NULL, NULL),
86-
('[email protected]', true, 2, 14, NULL, NULL),
87-
('[email protected]', true, 2, 15, NULL, NULL),
88-
('[email protected]', true, 2, 16, NULL, NULL),
89-
('[email protected]', false, 2, 17, NULL, NULL),
90-
('[email protected]', false, 2, 18, NULL, NULL),
91-
('[email protected]', false, 2, 19, NULL, NULL),
92-
('[email protected]', false, 2, 20, NULL, NULL),
93-
('[email protected]', false, 2, NULL, NULL, NULL);
94-
`);
92+
const name: Name = { first: null, last: null };
93+
const name1: Name = { first: 'firstname1', last: 'lastname1' };
94+
await this.save(usersRepo, User, [
95+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 1, name: name1 },
96+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 2, name },
97+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 3, name },
98+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 4, name },
99+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 5, name },
100+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 6, name },
101+
{ email: '[email protected]', isActive: false, companyId: 1, profileId: 7, name },
102+
{ email: '[email protected]', isActive: false, companyId: 1, profileId: 8, name },
103+
{ email: '[email protected]', isActive: false, companyId: 1, profileId: 9, name },
104+
{ email: '[email protected]', isActive: true, companyId: 1, profileId: 10, name },
105+
{ email: '[email protected]', isActive: true, companyId: 2, profileId: 11, name },
106+
{ email: '[email protected]', isActive: true, companyId: 2, profileId: 12, name },
107+
{ email: '[email protected]', isActive: true, companyId: 2, profileId: 13, name },
108+
{ email: '[email protected]', isActive: true, companyId: 2, profileId: 14, name },
109+
{ email: '[email protected]', isActive: true, companyId: 2, profileId: 15, name },
110+
{ email: '[email protected]', isActive: true, companyId: 2, profileId: 16, name },
111+
{ email: '[email protected]', isActive: false, companyId: 2, profileId: 17, name },
112+
{ email: '[email protected]', isActive: false, companyId: 2, profileId: 18, name },
113+
{ email: '[email protected]', isActive: false, companyId: 2, profileId: 19, name },
114+
{ email: '[email protected]', isActive: false, companyId: 2, profileId: 20, name },
115+
{ email: '[email protected]', isActive: false, companyId: 2, profileId: null, name },
116+
]);
95117

96118
// licenses
97-
await queryRunner.query(`
98-
INSERT INTO public.licenses ("name") VALUES
99-
('License1'),
100-
('License2'),
101-
('License3'),
102-
('License4'),
103-
('License5');
104-
`);
119+
await this.save(licensesRepo, License, [
120+
{ name: 'License1' },
121+
{ name: 'License2' },
122+
{ name: 'License3' },
123+
{ name: 'License4' },
124+
{ name: 'License5' },
125+
]);
105126

106127
// user-licenses
107-
await queryRunner.query(`
108-
INSERT INTO public.user_licenses ("userId", "licenseId", "yearsActive") VALUES
109-
(1, 1, 3),
110-
(1, 2, 5),
111-
(1, 4, 7),
112-
(2, 5, 1);
113-
`);
128+
await this.save(usersLincesesRepo, UserLicense, [
129+
{ userId: 1, licenseId: 1, yearsActive: 3 },
130+
{ userId: 1, licenseId: 2, yearsActive: 5 },
131+
{ userId: 1, licenseId: 4, yearsActive: 7 },
132+
{ userId: 2, licenseId: 5, yearsActive: 1 },
133+
]);
114134

115135
// user-projects
116-
await queryRunner.query(`
117-
INSERT INTO public.user_projects ("projectId", "userId", "review") VALUES
118-
(1, 1, 'User project 1 1'),
119-
(1, 2, 'User project 1 2'),
120-
(2, 2, 'User project 2 2'),
121-
(3, 3, 'User project 3 3');
122-
`);
136+
await this.save(usersProjectsRepo, UserProject, [
137+
{ projectId: 1, userId: 1, review: 'User project 1 1' },
138+
{ projectId: 1, userId: 2, review: 'User project 1 2' },
139+
{ projectId: 2, userId: 2, review: 'User project 2 2' },
140+
{ projectId: 3, userId: 3, review: 'User project 3 3' },
141+
]);
123142
}
124143

125144
public async down(queryRunner: QueryRunner): Promise<any> {}

integration/shared/https-exception.filter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export class HttpExceptionFilter implements ExceptionFilter {
1212
}
1313

1414
prepareException(exc: any): { status: number; json: object } {
15+
if (process.env.NODE_ENV !== 'test') {
16+
console.log(exc);
17+
}
18+
1519
const error =
1620
exc instanceof HttpException ? exc : new InternalServerErrorException(exc.message);
1721
const status = error.getStatus();

package.json

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,19 @@
1414
"rebuild": "yarn clean && yarn build",
1515
"build": "yarn s build",
1616
"clean": "yarn s clean",
17-
"pretest": "npm run db:prepare:typeorm",
18-
"test": "yarn s test",
19-
"pretest:coveralls": "yarn pretest",
20-
"test:coveralls": "yarn s test.coveralls",
17+
"test": "npx jest --runInBand -c=jest.config.js packages/ --verbose",
18+
"test:coverage": "yarn test:all --coverage",
19+
"test:coveralls": "yarn test:coverage --coverageReporters=text-lcov | coveralls",
20+
"test:all": "yarn test:mysql && yarn test:postgres",
21+
"test:postgres": "yarn db:prepare:typeorm && yarn test",
22+
"test:mysql": "yarn db:prepare:typeorm:mysql && TYPEORM_CONNECTION=mysql yarn test",
2123
"start:typeorm": "npx nodemon -w ./integration/crud-typeorm -e ts node_modules/ts-node/dist/bin.js integration/crud-typeorm/main.ts",
22-
"db:sync:typeorm": "cd ./integration/crud-typeorm && npx ts-node -r tsconfig-paths/register ../../node_modules/typeorm/cli.js schema:sync -f=orm",
23-
"db:drop:typeorm": "cd ./integration/crud-typeorm && npx ts-node -r tsconfig-paths/register ../../node_modules/typeorm/cli.js schema:drop -f=orm",
24-
"db:seeds:typeorm": "cd ./integration/crud-typeorm && npx ts-node -r tsconfig-paths/register ../../node_modules/typeorm/cli.js migration:run -f=orm",
25-
"db:prepare:typeorm": "npm run db:drop:typeorm && npm run db:sync:typeorm && npm run db:seeds:typeorm",
24+
"db:cli:typeorm": "cd ./integration/crud-typeorm && npx ts-node -r tsconfig-paths/register ../../node_modules/typeorm/cli.js",
25+
"db:sync:typeorm": "yarn db:cli:typeorm schema:sync -f=orm",
26+
"db:drop:typeorm": "yarn db:cli:typeorm schema:drop -f=orm",
27+
"db:seeds:typeorm": "yarn db:cli:typeorm migration:run -f=orm",
28+
"db:prepare:typeorm": "yarn db:drop:typeorm && yarn db:sync:typeorm && yarn db:seeds:typeorm",
29+
"db:prepare:typeorm:mysql": "yarn db:drop:typeorm -c=mysql && yarn db:sync:typeorm -c=mysql && yarn db:seeds:typeorm -c=mysql",
2630
"format": "npx pretty-quick --pattern \"packages/**/!(*.d).ts\"",
2731
"lint": "npx tslint 'packages/**/*.ts'",
2832
"cm": "npx git-cz",
@@ -74,6 +78,7 @@
7478
"jest": "24.9.0",
7579
"jest-extended": "0.11.2",
7680
"lerna": "3.16.4",
81+
"mysql": "^2.18.1",
7782
"nodemon": "1.19.2",
7883
"npm-check": "5.9.0",
7984
"nps": "5.9.8",

0 commit comments

Comments
 (0)