@@ -20,123 +20,111 @@ LoopBack offers two ways to do this:
2020- ** Auto-update** : Change database schema objects if there is a difference
2121 between the objects and model definitions. Existing data will be kept.
2222
23- ## Implementation Example
23+ {% include warning.html content="Auto-update will attempt to preserve data while
24+ updating the schema in your target database, but this is not guaranteed to be
25+ safe.
2426
25- Below is an example of how to implement
26- [ automigrate()] ( http://apidocs.loopback.io/loopback-datasource-juggler/#datasource-prototype-automigrate )
27- and
28- [ autoupdate()] ( http://apidocs.loopback.io/loopback-datasource-juggler/#datasource-prototype-autoupdate ) ,
29- shown with the
30- [ TodoList] ( https://loopback.io/doc/en/lb4/todo-list-tutorial.html ) example.
27+ Please check the documentation for your specific connector(s) for a detailed
28+ breakdown of behaviors for automigrate! " %}
3129
32- Create a new file ** src/migrate.ts ** and add the following import statement:
30+ ## Examples
3331
34- ``` ts
35- import { DataSource , Repository } from ' @loopback/ repository' ;
36- ```
37-
38- Import your application and your repositories:
32+ LoopBack applications are typically using ` RepositoryMixin ` to enhance the core
33+ ` Application ` class with additional repository-related APIs. One of such methods
34+ is ` migrateSchema ` , which iterates over all registered repositories and asks
35+ them to migrate their schema. Repositories that do not support schema migrations
36+ are silently skipped.
3937
40- ``` ts
41- import {TodoListApplication } from ' ./index' ;
42- import {TodoRepository , TodoListRepository } from ' ./repositories' ;
43- ```
38+ In the future, we would like to provide finer-grained control of database schema
39+ updates, learn more in the GitHub issue
40+ [ #487 Database Migration Management Framework] ( https://github.com/strongloop/loopback-next/issues/487 )
4441
45- Create a function called _ dsMigrate() _ :
42+ ### Auto-update database at start
4643
47- ``` ts
48- export async function dsMigrate(app : TodoListApplication ) {}
49- ```
50-
51- In the _ dsMigrate()_ function, get your datasource and instantiate your
52- repositories by retrieving them, so that the models are attached to the
53- corresponding datasource:
54-
55- ``` ts
56- const ds = await app .get <DataSource >(' datasources.db' );
57- const todoRepo = await app .getRepository (TodoRepository );
58- const todoListRepo = await app .getRepository (TodoListRepository );
59- ```
44+ To automatically update the database schema whenever the application is started,
45+ modify your main script to execute ` app.migrateSchema() ` after the application
46+ was bootstrapped (all repositories were registered) but before it is actually
47+ started.
6048
61- Then, in the same function, call _ automigrate() _ :
49+ {% include code-caption.html content="src/index.ts" %}
6250
6351``` ts
64- await ds .automigrate ();
65- ```
66-
67- This call to automigrate will migrate all the models attached to the datasource
68- db. However if you want to only migrate some of your models, add the names of
69- the classes in the first parameter:
52+ export async function main(options : ApplicationConfig = {}) {
53+ const app = new TodoListApplication (options );
54+ await app .boot ();
55+ await app .migrateSchema ();
56+ await app .start ();
7057
71- ``` ts
72- // Migrate a single model
73- ds .automigrate (' Todo' );
74- ```
58+ const url = app .restServer .url ;
59+ console .log (` Server is running at ${url } ` );
7560
76- ``` ts
77- // Migrate multiple models
78- ds .automigrate ([' Todo' , ' TodoList' ]);
61+ return app ;
62+ }
7963```
8064
81- The implementation for _ autoupdate()_ is similar. Create a new function
82- _ dsUpdate()_ :
83-
84- ``` ts
85- export async function dsUpdate(app : TodoListApplication ) {
86- const ds = await app .get <DataSource >(' datasources.db' );
87- const todoRepo = await app .getRepository (TodoRepository );
88- const todoListRepo = await app .getRepository (TodoListRepository );
65+ ### Auto-update the database explicitly
8966
90- await ds . autoupdate ();
91- }
92- ```
67+ It's usually better to have more control about the database migration and
68+ trigger the updates explicitly. To do so, you can implement a custom script as
69+ shown below.
9370
94- The completed ** src/migrate.ts** should look similar to this:
71+ {% include code-caption.html content=" src/migrate.ts" %}
9572
9673``` ts
97- import {DataSource , Repository } from ' @loopback/repository' ;
98- import {TodoListApplication } from ' ./index' ;
99- import {TodoRepository , TodoListRepository } from ' ./repositories' ;
74+ import {TodoListApplication } from ' ./application' ;
10075
101- export async function dsMigrate(app : TodoListApplication ) {
102- const ds = await app .get <DataSource >(' datasources.db' );
103- const todoRepo = await app .getRepository (TodoRepository );
104- const todoListRepo = await app .getRepository (TodoListRepository );
76+ export async function migrate(args : string []) {
77+ const dropExistingTables = args .includes (' --rebuild' );
78+ console .log (' Migrating schemas (%s)' , rebuild ? ' rebuild' : ' update' );
10579
106- await ds .automigrate ();
80+ const app = new TodoListApplication ();
81+ await app .boot ();
82+ await app .migrateSchema ({dropExistingTables });
10783}
10884
109- export async function dsUpdate(app : TodoListApplication ) {
110- const ds = await app .get <DataSource >(' datasources.db' );
111- const todoRepo = await app .getRepository (TodoRepository );
112- const todoListRepo = await app .getRepository (TodoListRepository );
113-
114- await ds .autoupdate ();
115- }
85+ migrate (process .argv ).catch (err => {
86+ console .error (' Cannot migrate database schema' , err );
87+ process .exit (1 );
88+ });
11689```
11790
118- Finally, in ** src/index.ts** , import and call the _ dsMigrate()_ or _ dsUpdate()_
119- function:
91+ After you have compiled your application via ` npm run build ` , you can update
92+ your database by running ` node dist/src/migrate ` and rebuild it from scratch by
93+ running ` node dist/src/migrate --rebuild ` . It is also possible to save this
94+ commands as ` npm ` scripts in your ` package.json ` file.
12095
121- ``` ts
122- import {TodoListApplication } from ' ./application' ;
123- import {ApplicationConfig } from ' @loopback/core' ;
124-
125- // Import the functions from src/migrate.ts
126- import {dsMigrate , dsUpdate } from ' ./migrate' ;
96+ ### Implement additional migration steps
12797
128- export {TodoListApplication };
98+ In some scenarios, the application may need to define additional schema
99+ constraints or seed the database with predefined model instances. This can be
100+ achieved by overriding the ` migrateSchema ` method provided by the mixin.
129101
130- export async function main(options : ApplicationConfig = {}) {
131- const app = new TodoListApplication (options );
132- await app .boot ();
133- await app .start ();
102+ The example below shows how to do so in our Todo example application.
134103
135- const url = app .restServer .url ;
136- console .log (` Server is running at ${url } ` );
104+ {% include code-caption.html content="src/application.ts" %}
137105
138- // The call to dsMigrate(), or replace with dsUpdate()
139- await dsMigrate (app );
140- return app ;
106+ ``` ts
107+ import {TodoRepository } from ' ./repositories' ;
108+ // skipped: other imports
109+
110+ export class TodoListApplication extends BootMixin (
111+ ServiceMixin (RepositoryMixin (RestApplication )),
112+ ) {
113+ // skipped: the constructor, etc.
114+
115+ async migrateSchema(options ? : SchemaMigrationOptions ) {
116+ // 1. Run migration scripts provided by connectors
117+ await super .migrateSchema (options );
118+
119+ // 2. Make further changes. When creating predefined model instances,
120+ // handle the case when these instances already exist.
121+ const todoRepo = await this .getRepository (TodoRepository );
122+ const found = await todoRepo .findOne ({where: {title: ' welcome' }});
123+ if (found ) {
124+ todoRepo .updateById (found .id , {isComplete: false });
125+ } else {
126+ await todoRepo .create ({title: ' welcome' , isComplete: false });
127+ }
128+ }
141129}
142130```
0 commit comments