-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmigrations.js
More file actions
233 lines (208 loc) · 5.86 KB
/
migrations.js
File metadata and controls
233 lines (208 loc) · 5.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/**
* Meteor Migration
*
* Simple database migrations for meteor
*
* @author idmontie
*/
/* global console */
// =================
// Meteor Migrations
// =================
Migrations = {
/**
* Meteor collection to store data in
* TODO settings should dictate what db to use.
*/
warehouse : new Meteor.Collection( 'meteor-migrations' ),
/**
* Add a migration. Will run the given migration once and only
* once, even when the app is restarted.
*
* Returns true if a migration of the same name is not already added.
* Returns false if otherwise.
*
* Migration names should be globally unique.
*
* The order number is an optional parameter that sets what
* order the migrations should be run in. Migrations are run
* from smallest order number to largest order number. If an
* order number is not provided, the largest order number + 10
* is used.
*
* @param String name Name of the migration
* @param Function migrationCallback The function to run once and only once
* @param Number order Optional order number
* @return boolean
*/
add : function ( name, migrationCallback, rollbackCallback, order ) {
'use strict';
// If we are called with less than 4 arguments, than assume
// that we are being called with the following signature:
// ( name, migrationCallback, order )
if ( arguments.length < 4 ) {
order = rollbackCallback;
rollbackCallback = null;
}
var found = false
for ( var i = 0; i < Migrations.migrations.length; i++ ) {
if ( name == Migrations.migrations[i].name ) {
found = true
break
}
}
if ( ! found ) {
if ( order == null ) {
order = Migrations.largestOrderNumber + 10
Migrations.largestOrderNumber = order
} else if ( order > Migrations.largestOrderNumber ) {
Migrations.largestOrderNumber = order
}
Migrations.migrations.push( {
migrationCallback: migrationCallback,
rollbackCallback: rollbackCallback,
name: name,
order: order
} )
return true
} else {
return false
}
},
/**
* Removes the migration from the current queue.
* This does NOT remove the migration from the collection of
* previously run migrations.
*
* To remove a migration to allow it to rerun, use removeFromDatabase.
*
* @param String name Name of the migration
*/
remove : function ( name ) {
'use strict';
for ( var i = 0; i < Migrations.migrations.length; i++ ) {
if ( Migrations.migrations[i].name == name ) {
delete Migrations.migrations[i];
}
}
},
/**
* Removes the migration from the database, so that it can be run again.
*
* @param String name Name of the migration
*/
removeFromDatabase : function ( name ) {
'use strict';
// TODO settings should dictate what db to use
Migrations.warehouse.remove( {
name : name
} )
},
/**
* Changes which function to run when the migration is performed.
*
* If the migration with the given name has already been run, this will
* NOT force a re-run of the migration. This is only available to override
* which migration to run.
*
* @param String name Name of the migration
* @param Function newMigrationCallback The new function to run once and only once
*/
update : function ( name, newMigrationCallback, order ) {
'use strict';
for ( var i = 0; i < Migrations.migrations.length; i++ ) {
if ( name == Migrations.migrations[i].name ) {
if ( order == null ) {
order = Migrations.migrations[i].order
} else if ( order > Migrations.largestOrderNumber ) {
Migrations.largestOrderNumber = order
}
}
Migrations.migrations[i] = {
migrationCallback: newMigrationCallback,
name: name,
order: order
}
}
},
/**
* Rollback a given migration. The migration will be rerun on start up since
* this also removes the migration from the database.
*
* @param String name The name of the migration to rollback
*/
rollback : function ( name ) {
for ( var i = 0; i < Migrations.migrations.length; i++ ) {
if ( Migrations.migrations[i].name == name ) {
if ( Migrations.migrations[i].rollbackCallback ) {
Migrations.migrations[i].rollbackCallback();
}
}
}
Migrations.removeFromDatabase( name );
},
/**
* Enables console logs for already run migrations.
*
* @type boolean
*/
verbose : false,
/**
* Array of migration objects. Do not use directly.
*
* Initially empty, no migrations to run
*
* Object structure:
*
* - orderNumber
* - name
* - migrationCallback
*
* @type Array
*/
migrations : [],
/**
* Stores the largest order number
*
* @type Number
*/
largestOrderNumber : 0
};
// ==============
// Meteor Startup
// ==============
Meteor.startup( function () {
'use strict';
/*
* Migrations are unsorted. Sort them and do them in order of
* smallest to largest order number
*/
Migrations.migrations.sort( function ( a, b ) {
if ( a.order < b.order ) {
return -1;
} else if ( a.order > b.order ) {
return 1;
} else {
return 0;
}
} )
for ( var i = 0; i < Migrations.migrations.length; i++ ) {
var migration = Migrations.migrations[i]
// Do the migration
var pastMigration = Migrations.warehouse.findOne( {
name : migration.name
} )
if ( ! pastMigration ) {
console.log ( '> Starting ' + migration.name + ' migration.' )
migration.migrationCallback()
Migrations.warehouse.insert( {
name : migration.name
} )
console.log ( '> Finishing ' + migration.name + ' migration.' )
} else {
if ( Migrations.verbose ) {
console.log( '> Skipping ' + migration.name + '.' )
}
}
}
} )