Skip to content

Commit

Permalink
Merge 3c987dc into 2a6465f
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelyali committed Oct 3, 2019
2 parents 2a6465f + 3c987dc commit b2dfabb
Show file tree
Hide file tree
Showing 11 changed files with 185 additions and 18 deletions.
1 change: 1 addition & 0 deletions integration/crud-typeorm/projects/index.ts
@@ -1,2 +1,3 @@
export * from './project.entity';
export * from './user-project.entity';
export * from './projects.service';
21 changes: 19 additions & 2 deletions integration/crud-typeorm/projects/project.entity.ts
@@ -1,4 +1,4 @@
import { Entity, Column, ManyToOne, ManyToMany, JoinTable } from 'typeorm';
import { Entity, Column, ManyToOne, ManyToMany, JoinTable, OneToMany } from 'typeorm';
import {
IsOptional,
IsString,
Expand All @@ -12,6 +12,7 @@ import { CrudValidationGroups } from '@nestjsx/crud';
import { BaseEntity } from '../base-entity';
import { Company } from '../companies/company.entity';
import { User } from '../users/user.entity';
import { UserProject } from './user-project.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

Expand Down Expand Up @@ -46,6 +47,22 @@ export class Project extends BaseEntity {
company?: Company;

@ManyToMany((type) => User, (u) => u.projects, { cascade: true })
@JoinTable()
@JoinTable({
name: 'user_projects',
joinColumn: {
name: 'projectId',
referencedColumnName: 'id',
},
inverseJoinColumn: {
name: 'userId',
referencedColumnName: 'id',
},
})
users?: User[];

@OneToMany((type) => UserProject, (el) => el.project, {
persistence: false,
onDelete: 'CASCADE',
})
userProjects!: UserProject[];
}
29 changes: 29 additions & 0 deletions integration/crud-typeorm/projects/user-project.entity.ts
@@ -0,0 +1,29 @@
import { Entity, Column, ManyToOne, PrimaryColumn } from 'typeorm';

import { User } from '../users/user.entity';
import { Project } from './project.entity';

@Entity('user_projects')
export class UserProject {
@PrimaryColumn()
public projectId!: number;

@PrimaryColumn()
public userId!: number;

@Column({ nullable: true })
public review!: string;

@ManyToOne((type) => Project, (el) => el.userProjects, {
primary: true,
persistence: false,
onDelete: 'CASCADE',
})
public project: Project;

@ManyToOne((type) => User, (el) => el.userProjects, {
primary: true,
persistence: false,
})
public user: User;
}
30 changes: 29 additions & 1 deletion integration/crud-typeorm/seeds.ts
Expand Up @@ -42,7 +42,7 @@ export class Seeds1544303473346 implements MigrationInterface {
('Project20', 'description20', false, 10);
`);

// users-profiles
// user-profiles
await queryRunner.query(`
INSERT INTO public.user_profiles ("name") VALUES
('User1'),
Expand Down Expand Up @@ -92,6 +92,34 @@ export class Seeds1544303473346 implements MigrationInterface {
('20@email.com', false, 2, 20, NULL, NULL),
('21@email.com', false, 2, NULL, NULL, NULL);
`);

// licenses
await queryRunner.query(`
INSERT INTO public.licenses ("name") VALUES
('License1'),
('License2'),
('License3'),
('License4'),
('License5');
`);

// user-licenses
await queryRunner.query(`
INSERT INTO public.user_licenses ("userId", "licenseId", "yearsActive") VALUES
(1, 1, 3),
(1, 2, 5),
(1, 4, 7),
(2, 5, 1);
`);

// user-projects
await queryRunner.query(`
INSERT INTO public.user_projects ("projectId", "userId", "review") VALUES
(1, 1, 'User project 1 1'),
(1, 2, 'User project 1 2'),
(2, 2, 'User project 2 2'),
(3, 3, 'User project 3 3');
`);
}

public async down(queryRunner: QueryRunner): Promise<any> {}
Expand Down
2 changes: 2 additions & 0 deletions integration/crud-typeorm/users-licenses/index.ts
@@ -0,0 +1,2 @@
export * from './license.entity';
export * from './user-license.entity';
12 changes: 12 additions & 0 deletions integration/crud-typeorm/users-licenses/license.entity.ts
@@ -0,0 +1,12 @@
import { Column, Entity } from 'typeorm';
import { BaseEntity } from '../base-entity';
import { IsOptional, IsString, MaxLength } from 'class-validator';

@Entity('licenses')
export class License extends BaseEntity {
@IsOptional({ always: true })
@IsString({ always: true })
@MaxLength(32, { always: true })
@Column({ type: 'varchar', length: 32, nullable: true, default: null })
name: string;
}
24 changes: 24 additions & 0 deletions integration/crud-typeorm/users-licenses/user-license.entity.ts
@@ -0,0 +1,24 @@
import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
import { User } from '../users/user.entity';
import { Type } from 'class-transformer';
import { License } from './license.entity';

@Entity('user_licenses')
export class UserLicense {
@PrimaryColumn()
userId: number;

@PrimaryColumn()
licenseId: number;

@ManyToOne((type) => User)
@Type((t) => User)
user: User;

@ManyToOne((type) => License)
@Type((t) => License)
license: License;

@Column()
yearsActive: number;
}
30 changes: 25 additions & 5 deletions integration/crud-typeorm/users/user.entity.ts
@@ -1,4 +1,12 @@
import { Entity, Column, JoinColumn, OneToOne, ManyToOne, ManyToMany } from 'typeorm';
import {
Entity,
Column,
JoinColumn,
OneToOne,
OneToMany,
ManyToOne,
ManyToMany,
} from 'typeorm';
import {
IsOptional,
IsString,
Expand All @@ -13,22 +21,23 @@ import { CrudValidationGroups } from '@nestjsx/crud';

import { BaseEntity } from '../base-entity';
import { UserProfile } from '../users-profiles/user-profile.entity';
import { UserLicense } from '../users-licenses/user-license.entity';
import { Company } from '../companies/company.entity';
import { Project } from '../projects/project.entity';
import { UserProject } from '../projects/user-project.entity';

const { CREATE, UPDATE } = CrudValidationGroups;

export class Name {
export class Name {
@IsString({ always: true })
@Column({ nullable: true })
first: string;

@IsString({ always: true })
@Column({ nullable: true })
last: string;
}


// tslint:disable-next-line:max-classes-per-file
@Entity('users')
export class User extends BaseEntity {
Expand All @@ -47,7 +56,7 @@ export class User extends BaseEntity {
isActive: boolean;

@Type((t) => Name)
@Column(type => Name)
@Column((type) => Name)
name: Name;

@Column({ nullable: true })
Expand All @@ -73,4 +82,15 @@ export class User extends BaseEntity {

@ManyToMany((type) => Project, (c) => c.users)
projects?: Project[];

@OneToMany((type) => UserProject, (el) => el.user, {
persistence: false,
onDelete: 'CASCADE',
})
userProjects?: UserProject[];

@OneToMany((type) => UserLicense, (ul) => ul.user)
@Type((t) => UserLicense)
@JoinColumn()
userLicenses?: UserLicense[];
}
16 changes: 7 additions & 9 deletions packages/crud-typeorm/src/typeorm-crud.service.ts
Expand Up @@ -414,10 +414,9 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
[curr.propertyName]: {
name: curr.propertyName,
columns: curr.inverseEntityMetadata.columns.map((col) => col.propertyName),
referencedColumn: (curr.joinColumns.length
? curr.joinColumns[0]
: curr.inverseRelation.joinColumns[0]
).referencedColumn.propertyName,
primaryColumns: curr.inverseEntityMetadata.primaryColumns.map(
(col) => col.propertyName,
),
},
}),
{},
Expand Down Expand Up @@ -521,10 +520,9 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
this.entityRelationsHash[cond.field] = {
name: curr.propertyName,
columns: curr.inverseEntityMetadata.columns.map((col) => col.propertyName),
referencedColumn: (curr.joinColumns.length
? /* istanbul ignore next */ curr.joinColumns[0]
: curr.inverseRelation.joinColumns[0]
).referencedColumn.propertyName,
primaryColumns: curr.inverseEntityMetadata.primaryColumns.map(
(col) => col.propertyName,
),
nestedRelation: curr.nestedRelation,
};
}
Expand All @@ -548,7 +546,7 @@ export class TypeOrmCrudService<T> extends CrudService<T> {
: cond.select.filter((col) => allowed.some((a) => a === col));

const select = [
relation.referencedColumn,
...relation.primaryColumns,
...(options.persist && options.persist.length ? options.persist : []),
...columns,
].map((col) => `${alias}.${col}`);
Expand Down
36 changes: 36 additions & 0 deletions packages/crud-typeorm/test/b.query-params.spec.ts
Expand Up @@ -52,6 +52,8 @@ describe('#crud-typeorm', () => {
persist: ['id'],
exclude: ['updatedAt', 'createdAt'],
},
users: {},
userProjects: {},
},
sort: [{ field: 'id', order: 'ASC' }],
limit: 100,
Expand Down Expand Up @@ -98,6 +100,7 @@ describe('#crud-typeorm', () => {
join: {
company: {},
'company.projects': {},
userLicenses: {},
},
},
})
Expand Down Expand Up @@ -437,6 +440,39 @@ describe('#crud-typeorm', () => {
done();
});
});
it('should return joined entity with ManyToMany pivot table', (done) => {
const query = qb
.setJoin({ field: 'users' })
.setJoin({ field: 'userProjects' })
.query();
return request(server)
.get('/projects/1')
.query(query)
.end((_, res) => {
expect(res.status).toBe(200);
expect(res.body.users).toBeDefined();
expect(res.body.users.length).toBe(2);
expect(res.body.users[0].id).toBe(1);
expect(res.body.userProjects).toBeDefined();
expect(res.body.userProjects.length).toBe(2);
expect(res.body.userProjects[0].review).toBe('User project 1 1');
done();
});
});
});

describe('#query composite key join', () => {
it('should return joined relation', (done) => {
const query = qb.setJoin({ field: 'userLicenses' }).query();
return request(server)
.get('/users/1')
.query(query)
.end((_, res) => {
expect(res.status).toBe(200);
expect(res.body.userLicenses).toBeDefined();
done();
});
});
});

describe('#sort', () => {
Expand Down
2 changes: 1 addition & 1 deletion packages/crud-typeorm/test/c.basic-crud.spec.ts
Expand Up @@ -280,7 +280,7 @@ describe('#crud-typeorm', () => {
});
});
it('should return saved entity with param', (done) => {
const dto: User = {
const dto: any = {
email: 'test@test.com',
isActive: true,
name: {
Expand Down

0 comments on commit b2dfabb

Please sign in to comment.