UNPKG

11.2 kBMarkdownView Raw
1# Wander
2
3Database Migrations for Modern Apps
4
5# Introduction
6
7__Wander__ is a command-line tool that enables programmable database changes. Through __Migrations__, you can version control your database and easily `commit` or `revert` changes between versions.
8
9# Supported Databases
10
11Currently, only `mysql` is supported. Adapters for other databases are still under development.
12
13+ ✓ MySQL
14+ ✗ PostgreSQL
15+ ✗ SQL Server
16+ ✗ Oracle DB
17
18# Getting Started
19
20To get started, globally install `wander-cli`
21
22```bash
23> npm install -g wander-cli
24```
25
26# Initializing Wander
27
28To initialize a new `wander` project, run `wander init` inside your project folder
29
30```bash
31> mkdir MyDatabase
32> cd MyDatabase
33> wander init
34```
35
36This will ask you for the name of your `migrations` folder (default: `./migrations`) and your database URI. Once completed, you can now start using wander.
37
38# Creating a new Migration
39
40To create a new migration, run `wander new <name>`.
41
42```bash
43> wander new create_post
44```
45
46This will create a new file inside your `migrations` folder
47
48```markdown
49+ migrations
50 - v1_0_0__create_post.js
51+ wrconfig.json
52+ .gitignore
53```
54
55> Note that you can change the type of version that your new migration will use, using the `-t` or `--version-type` option.
56
57```
58{major}.{minor}.{patch}
59```
60
61__Version Commands:__
62+ major: `wander new create_post -t major` (e.g. 2.0.0)
63+ minor: `wander new crete_post -t minor` (e.g. 1.1.0)
64+ patch: `wander new create_posrt -t patch` (e.g. 1.0.1)
65
66Once created, the file would look similar to the following.
67
68**v1_0_0__create_post.js**
69```javascript
70module.exports = {
71 version() {
72 return '1.0.0';
73 },
74 description() {
75 return `Create post`;
76 },
77 async up({}) {
78 },
79 async down({}) {
80 }
81};
82```
83
84__Description__
85
86+ The `version` method returns the version name of your migration.
87+ The `description` method returns the a brief description of your database changes. You can expand this as you wish.
88+ The `up` method runs whenever the migration is committed
89+ The `down` method runs whenever the migration is reverted
90
91For the `up` and `down` methods, an object is passed to them for your usage, which includes serveral useful functions. Check the [API](#api) section for more information.
92
93__Example__
94
95```javascript
96module.exports = {
97 version() {
98 return '1.0.0';
99 },
100 description() {
101 return `Create post`;
102 },
103 async up({ create, seed }) {
104 create('post', table => {
105 table.id();
106 table.string('caption');
107 table.timestamps();
108 });
109
110 seed('post', [
111 { caption: 'New post!' },
112 { caption: 'Another post!' }
113 ]);
114 },
115 async down({ drop, truncate }) {
116 truncate('post');
117 drop('post');
118 }
119};
120```
121
122# API
123
124## create
125
126__Parameters__
127
128| Paramter | Data type |
129| ---------- | ---------------------------------- |
130| tableName | string |
131| definition | (table: [Table](#table)) => void |
132
133__Description__
134
135+ Accepts a __tableName__ that you want to create, and a definition function.
136+ The definition function has a [Table](#table) parameter that allows you to define the structure of your table.
137
138__Example__
139
140```javascript
141create('post', table => {
142 table.id();
143 table.string('caption');
144 table.timestamps();
145});
146```
147
148## alter
149
150__Parameters__
151
152| Paramter | Data type |
153| ---------- | ---------------------------------------- |
154| tableName | string |
155| definition | (table: [Table](#table-class)) => void |
156
157__Description__
158
159+ Accepts a __tableName__ that you want to alter, and a definition function.
160+ The definition function has a [Table](#table-class) parameter that allows you to define the structure of your table.
161
162__Example__
163
164```javascript
165alter('comment', table => {
166 table.integer('comment_count').add();
167});
168```
169
170## drop
171
172__Parameters__
173
174| Paramter | Data type |
175| ---------- | ---------------------------------- |
176| tableName | string |
177
178__Description__
179
180+ Accepts a __tableName__ that you want to drop.
181
182__Example__
183
184```javascript
185drop('comment');
186```
187
188## seed
189
190__Parameters__
191
192| Paramter | Data type |
193| ---------- | ---------------------------------- |
194| tableName | string |
195| seeds | object[] |
196
197__Description__
198
199+ Accepts a __tableName__ that you want to seed with data.
200+ Accepts a __seeds__ array of objects defining the data you want to insert.
201
202> __NOTE:__ Only the columns of the first item in the list will define the columns that will be populated for all of the items.
203
204__Example__
205
206```javascript
207seed('post', [
208 { caption: 'A new post!' },
209 { capton: 'Another post' }
210]);
211```
212
213## truncate
214
215__Parameters__
216
217| Paramter | Data type |
218| ---------- | ---------------------------------- |
219| tableName | string |
220
221__Description__
222
223+ Accepts a __tableName__ that you want to truncate.
224
225__Example__
226
227```javascript
228truncate('comment');
229```
230
231## execute
232
233__Parameters__
234
235| Paramter | Data type |
236| ---------- | ---------------------------------- |
237| query | string |
238
239__Description__
240
241+ Ideal for running scripts that are too complex or are too specific to the database you are running.
242+ Accepts a __query__ that you want to execute.
243
244> WARNING: Running execute is very dangerous especially if the keys and values you are trying to use are not properly escaped.
245
246__Example__
247
248```javascript
249execute(`
250 SET sql_safe_updates = 0;
251 UPDATE post SET updated_at = now() WHERE id > 5;
252`);
253```
254
255
256# __Table__ class
257
258__Description__
259
260+ Allows you to define the structue of your table via different methods
261
262__Methods__
263
264+ id(`columnName`?: string)
265 - Adds a primary auto_increment key (default: `id`)
266+ string(`columnName`: string, `length`?: number)
267 - Adds a string column (e.g. on MySQL this is equivalent to `varchar`)
268+ text(`columnName`: string)
269 - Adds a text column (unlike string, there is no limit to the length)
270+ integer(`columnName`: string, `length`?: number)
271 - Adds an integer column
272+ float(`columnName`: string, `length`?: number, `precision`?: number)
273 - Adds a float column
274+ decimal(`columnName`: string, `length`?: number, `precision`?: number)
275 - Adds a decimal column
276+ double(`columnName`: string, `length`?: number, `precision`?: number)
277 - Adds a double column
278+ pointer(`tableName`: string, `via`?: string)
279 - Adds an integer column pointing to another table
280 - `via`, by default, is `tableName`_`id`
281+ date(`columnName`: string)
282 - Adds a date column
283+ datetime(`columnName`: string)
284 - Adds a datetime column
285+ boolean(`columnName`: string)
286 - Adds a boolean column (e.g. on MySQL this is equivalent to `bit`)
287+ json(`columnName`: string)
288 - Supported in `MySQL 5.7+`
289+ timestamps()
290 - Creates `created_at`, `updated_at` and `deleted_at` datetime columns
291+ index(`columnName`: string, `alias`?: string)
292 - Create an index on the table
293+ unique(`columnName`: string, `alias`?: string)
294 - Create a unique index on the table
295
296## Key Actions
297
298In addition, when using the `alter` option, the above methods have specific actions that need to be defined in order to let `wander` know how the columns are going to be changed.
299
300+ add()
301 - Add the column/index/unique key
302+ modify()
303 - Modify the column
304+ drop()
305 - Drop the column/index/unique key
306
307__Example__
308
309```javascript
310alter('comment', table => {
311 table.integer('comment_count').add();
312 table.index('IDENT').drop();
313});
314```
315
316# Sample migration
317
318```javascript
319module.exports = {
320 version() {
321 return '1.0.0';
322 },
323 description() {
324 return `
325 Created the post table.
326 Changed the comment table.
327 Populated the post table.
328 `;
329 },
330 async up({ create, alter, seed, execute }) {
331 create('post', table => {
332 table.id();
333 table.string('caption', 500);
334 table.pointer('user');
335 table.json('info');
336 table.string('identifier');
337 table.index('identifier', 'IDENT');
338 table.timestamps();
339 });
340
341 // Equivalent to the following
342 `
343 CREATE TABLE post (
344 id int AUTO_INCREMENT,
345 caption varchar(500),
346 user_id int(11),
347 info json,
348 identifier varchar(30),
349 PRIMARY KEY (id),
350 INDEX IDENT (identifier));
351 `
352
353 alter('comment', table => {
354 table.integer('like_count').add();
355 table.string('message', 250).modify();
356 table.pointer('post').drop();
357 table.index('IDENT').drop();
358 });
359
360 // Equivalent to the following
361 `
362 ALTER TABLE comment
363 ADD COLUMN like_count int,
364 MODIFY COLUMN message varchar(250),
365 DROP COLUMN post_id;
366 `
367
368 seed('post', [
369 { caption: 'New caption!' },
370 { caption: 'New caption!' },
371 { caption: 'New caption!' }
372 ]);
373
374 // Equivalent to the following
375 `
376 INSERT INTO post
377 (caption)
378 VALUES
379 ('New caption!'),
380 ('New caption!'),
381 ('New caption!');
382 `
383
384 execute(`
385 SET sql_safe_updates = 0;
386 UPDATE post SET privacy = 'public' WHERE role IS NULL;
387 `);
388 },
389 async down({ alter, drop, truncate }) {
390
391 truncate('post');
392 drop('post');
393
394 alter('comment', () => {
395 this.integer('like_count').drop();
396 this.string('message', 500).modify();
397 this.pointer('post').add();
398 this.index('identifier', 'IDENT').add();
399 });
400
401 execute(`UPDATE post SET privacy = 'private' WHERE role IS NULL`);
402 }
403};
404```
405
406# Up versus Down
407
408In terms of the `Migrations` standard for databases, the convention is to always have `up` and `down` methods.
409
410The purpose of the `up` method is to commit the changes you want to apply to the database. Conversely, it is required that you undo everything that you performed, inside the `down` method.
411
412The reason why this practice is observed is that it allows you, to some extent, to recover from a breaking change that was executed accidentally. Also, it allows you to ensure consistency when changing between database versions.
413
414Do note, however, that unless a `seed` option is defined inside the methods, any data that was __truncated__ or __dropped__ will be __lost__ forever.
415
416# Transactions
417
418For `wander`, all migrations are executed as a single transaction. That means the [MigrationOptions](#migrationoptions-object) you used will not be fired until the processor has gone through all of them.
419
420That also means that if anything goes wrong, the scripts will be rolled back (except for cases where database auto-commits occur). See the corresponding manuals of your databases for more information.
\No newline at end of file