Skip to content

Feature/#37 relation example #38

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 8, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,8 @@ All script are defined in the package.json file, but the most important ones are

### Database Migration

- Run `./node_modules/.bin/typeorm create -n <migration-file-name>` to create a new migration file.
- Run `typeorm migrations:create -n <migration-file-name>` to create a new migration file.
- Try `typeorm -h` to see more useful cli commands like generating migration out of your models.
- To migrate your database run `npm start db.migrate`.
- To revert your latest migration run `npm start db.revert`.
- Drops the complete database schema `npm start db.drop`.
Expand Down Expand Up @@ -267,19 +268,44 @@ factory.define(User, (faker: typeof Faker) => {
});
```

This is a nested example for a factory to get the foreign key of the other entity.
This can be used to pass some dynamic value into the factory.

```typescript
factory.define(Pet, (faker: typeof Faker, args: any[]) => {
const type = args[0];
return {
name: faker.name.firstName(),
type: type || 'dog',
userId: factory.get(User).returning('id')
type: type || 'dog'
};
});
```

To deal with relations you can use the entity manager like this.

```typescript
import { SeedsInterface, FactoryInterface, times } from '../../lib/seeds';
import { Pet } from '../../../src/api/models/Pet';
import { User } from '../../../src/api/models/User';

export class CreatePets implements SeedsInterface {

public async seed(factory: FactoryInterface): Promise<any> {
const connection = await factory.getConnection();
const em = connection.createEntityManager();

await times(10, async (n) => {
// This creates a pet in the database
const pet = await factory.get(Pet).create();
// This only returns a entity with fake data
const user = await factory.get(User).make();
user.pets = [pet];
await em.save(user);
});
}

}
```

### 2. Create a seed file

The seeds files define how much and how the data are connected with each other. The files will be executed alphabetically.
Expand Down
41 changes: 41 additions & 0 deletions src/api/controllers/PetController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { JsonController, Get, Post, Put, Param, Delete, Body, OnUndefined, Authorized } from 'routing-controllers';
import { PetService } from '../services/PetService';
import { Pet } from '../models/Pet';
import { PetNotFoundError } from '../errors/PetNotFoundError';


@Authorized()
@JsonController('/pets')
export class PetController {

constructor(
private petService: PetService
) { }

@Get()
public find(): Promise<Pet[]> {
return this.petService.find();
}

@Get('/:id')
@OnUndefined(PetNotFoundError)
public one( @Param('id') id: string): Promise<Pet | undefined> {
return this.petService.findOne(id);
}

@Post()
public create( @Body() pet: Pet): Promise<Pet> {
return this.petService.create(pet);
}

@Put('/:id')
public update( @Param('id') id: string, @Body() pet: Pet): Promise<Pet> {
return this.petService.update(id, pet);
}

@Delete('/:id')
public delete( @Param('id') id: string): Promise<void> {
return this.petService.delete(id);
}

}
7 changes: 7 additions & 0 deletions src/api/errors/PetNotFoundError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { HttpError } from 'routing-controllers';

export class PetNotFoundError extends HttpError {
constructor() {
super(404, 'Pet not found!');
}
}
27 changes: 27 additions & 0 deletions src/api/models/Pet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { IsNotEmpty } from 'class-validator';
import { User } from './User';


@Entity()
export class Pet {

@PrimaryGeneratedColumn('uuid')
public id: string;

@IsNotEmpty()
@Column()
public name: string;

@IsNotEmpty()
@Column()
public age: number;

@ManyToOne(type => User, user => user.pets)
public user: User;

public toString(): string {
return `${this.name}`;
}

}
6 changes: 5 additions & 1 deletion src/api/models/User.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
import { IsNotEmpty } from 'class-validator';
import { Pet } from './Pet';


@Entity()
Expand All @@ -20,6 +21,9 @@ export class User {
@Column()
public email: string;

@OneToMany(type => Pet, pet => pet.user)
public pets: Pet[];

public toString(): string {
return `${this.firstName} ${this.lastName} (${this.email})`;
}
Expand Down
7 changes: 7 additions & 0 deletions src/api/repositories/PetRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Repository, EntityRepository } from 'typeorm';
import { Pet } from '../models/Pet';

@EntityRepository(Pet)
export class PetRepository extends Repository<Pet> {

}
47 changes: 47 additions & 0 deletions src/api/services/PetService.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Service } from 'typedi';
import { OrmRepository } from 'typeorm-typedi-extensions';
import { PetRepository } from '../repositories/PetRepository';
import { Pet } from '../models/Pet';
import { events } from '../subscribers/events';
import { EventDispatcher, EventDispatcherInterface } from '../../decorators/EventDispatcher';
import { Logger, LoggerInterface } from '../../decorators/Logger';


@Service()
export class PetService {

constructor(
@OrmRepository() private petRepository: PetRepository,
@EventDispatcher() private eventDispatcher: EventDispatcherInterface,
@Logger(__filename) private log: LoggerInterface
) { }

public find(): Promise<Pet[]> {
this.log.info('Find all pets');
return this.petRepository.find();
}

public findOne(id: string): Promise<Pet | undefined> {
this.log.info('Find all pets');
return this.petRepository.findOne({ id });
}

public async create(pet: Pet): Promise<Pet> {
this.log.info('Create a new pet => ', pet.toString());
const newPet = await this.petRepository.save(pet);
this.eventDispatcher.dispatch(events.pet.created, newPet);
return newPet;
}

public update(id: string, pet: Pet): Promise<Pet> {
this.log.info('Update a pet');
pet.id = id;
return this.petRepository.save(pet);
}

public delete(id: string): Promise<void> {
this.log.info('Delete a pet');
return this.petRepository.removeById(id);
}

}
2 changes: 1 addition & 1 deletion src/api/services/UserService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class UserService {

public find(): Promise<User[]> {
this.log.info('Find all users');
return this.userRepository.find();
return this.userRepository.find({ relations: ['pets'] });
}

public findOne(id: string): Promise<User | undefined> {
Expand Down
3 changes: 3 additions & 0 deletions src/api/subscribers/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ export const events = {
user: {
created: 'onUserCreate',
},
pet: {
created: 'onPetCreate',
},
};
Loading