# Seeding

**Seeding** is about either loading the database with mocked entities and relations between them to test the system's functionalities, or setting predefined data for the production environment. Here, we'll use it for the former reason.

TypeORM currently has no support for seeding, so we can write a route for doing such. For organization, let's create a very simple seeding resource inside the database structure. Choose <mark style="color:red;">**no**</mark> for CRUD entry points.

```sh
nest g res database/seeding
```

In the **controller**, insert the route responsible for seeding.

```typescript
@Post()
seed() {
  return this.seedingService.seed();
}
```

In the **service**, we need to perform several database operations and **all of them** need to be <mark style="color:green;">successful</mark>. In case **any** of them <mark style="color:red;">fails</mark>, all of the already performed operations need to be **reverted back** in order to avoid inconsistencies. This means that we need to use a **transaction**.

To do so, first we need to inject in the service a <mark style="color:blue;">`DataSource`</mark>.

```typescript
constructor(private readonly dataSource: DataSource) {}
```

Now, inside the <mark style="color:blue;">`seed()`</mark> method, insert the basic transaction structure inside which we'll put the actual seed. You can consider this as boilerplate.

```typescript
async seed() {
  const queryRunner = this.dataSource.createQueryRunner();
  await queryRunner.connect();
  await queryRunner.startTransaction();
  try {
    // seed goes here

    await queryRunner.commitTransaction();
  } catch (error) {
    await queryRunner.rollbackTransaction();
    throw error;
  } finally {
    await queryRunner.release();
  }
}
```

The <mark style="color:blue;">`queryRunner`</mark> offers full control over the transaction, but we can also use a simpler approach that doesn't require using it, if possible. We should simply replace the boilerplate with this:

```typescript
await this.dataSource.transaction(async (manager) => {
  // seed goes here
})
```

Now, we can use the seed itself. The following steps occur:

* First, repositories are obtained from the <mark style="color:blue;">`manager`</mark>. Only these repositories are able to **rollback** in case of a failed operation.
* After that, the database tables are cleared. Note that some of them are not cleared directly because their records will be deleted due to <mark style="color:blue;">`cascade`</mark>.
* Finally, the entities and their relationships are created and saved in the database.

```typescript
const usersRepository = queryRunner.manager.getRepository(User);
const categoriesRepository = queryRunner.manager.getRepository(Category);
const productsRepository = queryRunner.manager.getRepository(Product);
const ordersRepository = queryRunner.manager.getRepository(Order);
const orderItemsRepository = queryRunner.manager.getRepository(OrderItem);
const paymentsRepository = queryRunner.manager.getRepository(Payment);

const orders = await ordersRepository.find();
await ordersRepository.remove(orders);
const users = await usersRepository.find();
await usersRepository.remove(users);
const products = await productsRepository.find();
await productsRepository.remove(products);
const categories = await categoriesRepository.find();
await categoriesRepository.remove(categories);

const cat1 = categoriesRepository.create({ name: 'Electronics' });
const cat2 = categoriesRepository.create({ name: 'Books' });
const cat3 = categoriesRepository.create({ name: 'Computers' });
const cat4 = categoriesRepository.create({ name: 'Games' });

await categoriesRepository.save([cat1, cat2, cat3, cat4]);

const p1 = productsRepository.create({
  name: 'Book of Cain',
  description: 'The writings of an elderly scholar about this perilous world.',
  price: 102.5,
  categories: [cat2],
});
const p2 = productsRepository.create({
  name: 'Smart TV',
  price: 2350,
  categories: [cat1, cat3],
});
const p3 = productsRepository.create({
  name: 'Macbook Pro',
  price: 1200,
  categories: [cat3],
});
const p4 = productsRepository.create({
  name: 'Gaming PC',
  description: 'Latest generation hardware for the best experience.',
  price: 2000,
  categories: [cat3],
});
const p5 = productsRepository.create({
  name: 'Game Mechanics: Advanced Game Design',
  description: 'Learn how to craft well-designed game mechanics.',
  price: 149.9,
  categories: [cat2],
});
const p6 = productsRepository.create({
  name: 'Warcraft III: Reign of Chaos',
  description: 'A true classic in the RTS genre.',
  price: 25.99,
  categories: [cat4],
});

await productsRepository.save([p1, p2, p3, p4, p5, p6]);

const u1 = usersRepository.create({
  name: 'Pedro Faria',
  email: 'jarulf@mail.com',
  phone: '988888888',
  password: '123456',
});
const u2 = usersRepository.create({
  name: 'Chris Metzen',
  email: 'chris@blizz.com',
  phone: '977777777',
  password: '654321',
});

await usersRepository.save([u1, u2]);

const oi1 = orderItemsRepository.create({
  product: p1,
  quantity: 2,
  price: p1.price,
});
const oi2 = orderItemsRepository.create({
  product: p3,
  quantity: 1,
  price: p3.price,
});
const oi3 = orderItemsRepository.create({
  product: p3,
  quantity: 2,
  price: p3.price,
});
const oi4 = orderItemsRepository.create({
  product: p5,
  quantity: 2,
  price: p5.price,
});

const pay1 = paymentsRepository.create();

const o1 = ordersRepository.create({
  customer: u1,
  items: [oi1, oi2],
  status: OrderStatus.AWAITING_SHIPMENT,
  payment: pay1,
});
const o2 = ordersRepository.create({
  customer: u2,
  items: [oi3],
  status: OrderStatus.AWAITING_PAYMENT,
});
const o3 = ordersRepository.create({
  customer: u1,
  items: [oi4],
  status: OrderStatus.AWAITING_PAYMENT,
});

await ordersRepository.save([o1, o2, o3]);
```

In the **Extra module 6 - Automated Testing**, we'll learn how to perform similar operations by simulating requests from a user. This is possible with the [supertest](https://www.npmjs.com/package/supertest) library. We'll also do so in a **dedicated database** purposed for testing.

<mark style="color:green;">**Commit**</mark> - Seeding
