Skip to content
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

fix(example-todo-list): add steps to run in sql db #2448

Merged
merged 1 commit into from
May 3, 2019
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
4 changes: 4 additions & 0 deletions docs/site/sidebars/lb4_sidebar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ children:
url: todo-list-tutorial-controller.html
output: 'web, pdf'

- title: 'Running on relational databases'
url: todo-list-tutorial-sqldb.html
output: 'web, pdf'

- title: 'SOAP Web Service Tutorial'
url: soap-calculator-tutorial.html
output: 'web, pdf'
Expand Down
Binary file added docs/site/todo-list-tutorial-dbtables.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
143 changes: 143 additions & 0 deletions docs/site/todo-list-tutorial-sqldb.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
---
lang: en
title: 'Running on relational databases'
keywords: LoopBack 4.0, LoopBack 4
sidebar: lb4_sidebar
permalink: /doc/en/lb4/todo-list-tutorial-sqldb.html
summary:
LoopBack 4 TodoList Application Tutorial - Running on Relational Databases
---

If you are running this example using a relational database, there are extra
steps in order to set up constraints in the database. We're using PostgreSQL for
illustration, but it would work for other relational databases in a similar way.

### Create a new datasource

We're going to update the DataSource `db` to connect to the PostgreSQL database
instead of the in-memory database.

First, remove the existing `db`, run:

```sh
rm src/datasources/db.datasource.*
```

Then, create the datasource with the same name with the `lb4 datasource` command
and select `PostgreSQL` as the connector.

```sh
$ lb4 datasource
? Datasource name: db
? Select the connector for db:
Redis key-value connector (supported by StrongLoop)
MongoDB (supported by StrongLoop)
MySQL (supported by StrongLoop)
❯ PostgreSQL (supported by StrongLoop)
Oracle (supported by StrongLoop)
Microsoft SQL (supported by StrongLoop)
REST services (supported by StrongLoop)
...
```

### Specify the foreign key constraint in the models

Based on the model relations we've specified in the 3 models, the expected
database tables look like below:
![database tables](todo-list-tutorial-dbtables.png)

{% include note.html content="
There is ongoing work on supporting strong relations with referential integrity. For details, please see [epic #2231](https://github.com/strongloop/loopback-next/issues/2331).
" %}

#### Specify the foreign key constraints in Todo model

We will use the `foreignKeys` attribute to determine the constraints in the
database table.

In `src/models/todo.model.ts`, add the `settings` options in the `@model`
decorator.

```ts
@model({
settings: {
foreignKeys: {
fk_todo_todoListId: {
name: 'fk_todo_todoListId',
entity: 'TodoList',
entityKey: 'id',
foreignKey: 'todolistid',
},
},
},
})
export class Todo extends Entity {
//etc.
}
```
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add little bit more code to make the snippet self-contained. At the moment, it's breaking syntax highlighting here on GitHub.

export class Todo extends Entity {
  // etc.
}


Check out the details for
[auto-migrate and auto-update](https://loopback.io/doc/en/lb3/PostgreSQL-connector.html#auto-migrateauto-update-models-with-foreign-keys)
for PostgreSQL connector. For other connectors, go to the corresponding
connector from the
[Connectors Reference](https://loopback.io/doc/en/lb3/Connectors-reference.html)
section.

#### Specify the foreign key constraints in TodoListImage model

Similar to the `Todo` model, we will specify the constraints in the `settings`.

```ts
@model({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The FK definitions here seem the same as above ^

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will fix it as @jannyHou suggested.

settings: {
foreignKeys: {
fk_todoListImage_todoListId: {
name: 'fk_todoListImage_todoListId',
entity: 'TodoList',
entityKey: 'id',
foreignKey: 'todolistid',
},
},
},
})
export class TodoListImage extends Entity {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto.

export class TodoListImage extends Entity {
  // etc.
}

//etc.
}
```

### Database migration using `npm run migrate` command

The order of table creation is important. We are going to migrate `TodoList`
model before the `Todo` and `TodoListImage` models.

In `src/migrate.ts`, modify this line:

```ts
await app.migrateSchema({existingSchema});
```

to:

```ts
await app.migrateSchema({
existingSchema,
// The order of table creation is important.
// A referenced table must exist before creating a
// foreign key constraint.
// For PostgreSQL connector, it does not create tables in the
// right order. Therefore, this change is needed.
models: ['TodoList', 'Todo', 'TodoListImage'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you sure this line is necessary? I believe that app.migrateSchema is going to migrate ALL models by default. By omitting the list of models, we keep the code forward-compatible. In your proposal, developers adding new models in the future must remember to update the migration script too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my experiment, this line is necessary. TodoList table must be created first before Todo and TodoListImage. When I didn't specify the order, I will get an error about the TodoList table do not exist. I'm not sure what's the better way to specify the order but this change seems to be working for me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed with @bajtos. He suggested:

  1. Add comments in the above code snippet to explain why we need to do this. -- DONE
  2. Open a GH issue to investigate how we can improve the migration tool so that users don't need to explicitly specify the order. -- [Spike] Automigrate: no need to specify the order of tables to be migrated #2831 is created.

});
```

Run the following commands:

```sh
$ npm run build
$ npm run migrate
```

The `todolist`, `todo` and `todolistimage` tables are created.

For details, see the [Database migrations](Database-migrations.md) documentation
page.