root/trunk/grails-app/conf/DatabaseUpgrade.groovy @ 1689

Revision 1689, 12.1 KB (checked in by robert@…, 3 years ago)

Removed assayModule platform field (#387)

  • Property svn:keywords set to Rev Author Date
Line 
1import groovy.sql.Sql
2import dbnp.studycapturing.Study
3import org.codehaus.groovy.grails.commons.ConfigurationHolder
4
5/**
6 * A script to automatically perform database changes
7 *
8 * @Author Jeroen Wesbeek
9 * @Since 20101209
10 *
11 * Revision information:
12 * $Rev$
13 * $Author$
14 * $Date$
15 */
16class DatabaseUpgrade {
17        /**
18         * handle database upgrades
19         *
20         * @param dataSource
21         */
22        public static void handleUpgrades(dataSource) {
23                // get a sql instance
24                groovy.sql.Sql sql = new groovy.sql.Sql(dataSource)
25
26                // get configuration
27                def config = ConfigurationHolder.config
28                def db = config.dataSource.driverClassName
29
30                // execute per-change check and upgrade code
31                changeStudyDescription(sql, db)                         // r1245 / r1246
32                changeStudyDescriptionToText(sql, db)           // r1327
33                changeTemplateTextFieldSignatures(sql, db)      // prevent Grails issue, see http://jira.codehaus.org/browse/GRAILS-6754
34                setAssayModuleDefaultValues(sql, db)            // r1490
35                dropMappingColumnNameConstraint(sql, db)        // r1525
36                makeMappingColumnValueNullable(sql, db)         // r1525
37                alterStudyAndAssay(sql, db)                                     // r1594
38                fixDateCreatedAndLastUpdated(sql, db)
39                dropAssayModulePlatform(sql, db)                        // r1689
40        }
41
42        /**
43         * execute database change r1245 / r1246 if required
44         * @param sql
45         * @param db
46         */
47        public static void changeStudyDescription(sql, db) {
48                // check if we need to perform this upgrade
49                if (sql.firstRow("SELECT count(*) as total FROM template_field WHERE templatefieldentity='dbnp.studycapturing.Study' AND templatefieldname='Description'").total > 0) {
50                        // grom that we are performing the upgrade
51                        if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: study description".grom()
52
53                        // database upgrade required
54                        try {
55                                // get the template field id
56                                def id = sql.firstRow("SELECT id FROM template_field WHERE templatefieldentity='dbnp.studycapturing.Study' AND templatefieldname='Description'").id
57
58                                // iterate through all obsolete study descriptions
59                                sql.eachRow("SELECT study_id, template_text_fields_elt as description FROM study_template_text_fields WHERE template_text_fields_idx='Description'") { row ->
60                                        // migrate the template description to the study object itself
61                                        // so we don't have to bother with sql injections, etc
62                                        def study = Study.findById(row.study_id)
63                                        study.setFieldValue('description', row.description)
64                                        if (!(study.validate() && study.save())) {
65                                                throw new Exception("could not save study with id ${row.study_id}")
66                                        }
67                                }
68
69                                // delete all obsolete descriptions
70                                sql.execute("DELETE FROM study_template_text_fields WHERE template_text_fields_idx='Description'")
71
72                                // find all template id's where this field is used
73                                sql.eachRow("SELECT DISTINCT template_fields_id, fields_idx FROM template_template_field WHERE template_field_id=${id}") { row ->
74                                        // delete the template_template_field reference
75                                        sql.execute("DELETE FROM template_template_field WHERE template_field_id=${id} AND template_fields_id=${row.template_fields_id}")
76
77                                        // and lower the idx-es of the remaining fields
78                                        sql.execute("UPDATE template_template_field SET fields_idx=fields_idx-1 WHERE fields_idx>${row.fields_idx} AND template_fields_id=${row.template_fields_id}")
79                                }
80
81                                // and delete the obsolete template field
82                                sql.execute("DELETE FROM template_field WHERE id=${id}")
83                        } catch (Exception e) {
84                                println "changeStudyDescription database upgrade failed: " + e.getMessage()
85                        }
86                }
87        }
88
89        /**
90         * execute database change r1327 if required
91         * @param sql
92         * @param db
93         */
94        public static void changeStudyDescriptionToText(sql, db) {
95                // are we running postgreSQL ?
96                if (db == "org.postgresql.Driver") {
97                        // check if column 'description' in table 'study' is not of type 'text'
98                        if (sql.firstRow("SELECT count(*) as total FROM information_schema.columns WHERE columns.table_schema::text = 'public'::text AND columns.table_name='study' AND column_name='description' AND data_type != 'text'").total > 0) {
99                                // grom that we are performing the upgrade
100                                if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: study description to text".grom()
101
102                                // database upgrade required
103                                try {
104                                        // change the datatype of study::description to text
105                                        sql.execute("ALTER TABLE study ALTER COLUMN description TYPE text")
106                                } catch (Exception e) {
107                                        println "changeStudyDescriptionToText database upgrade failed: " + e.getMessage()
108                                }
109                        }
110                }
111        }
112
113        /**
114         * it appears that some TEXT template fields are not of type 'text'
115         * due to an issue in how Grails' GORM works with domain inheritance
116         * (see http://jira.codehaus.org/browse/GRAILS-6754)
117         * @param sql
118         * @param db
119         */
120        public static void changeTemplateTextFieldSignatures(sql, db) {
121                if (db == "org.postgresql.Driver") {
122                        // check if any TEXT template fields are of type 'text'
123                        sql.eachRow("SELECT columns.table_name as tablename FROM information_schema.columns WHERE columns.table_schema::text = 'public'::text AND column_name='template_text_fields_elt' AND data_type != 'text';")
124                                { row ->
125                                        if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: ${row.tablename} template_text_fields_string/elt to text".grom()
126                                        try {
127                                                // change the datatype of text fields to text
128                                                sql.execute(sprintf("ALTER TABLE %s ALTER COLUMN template_text_fields_elt TYPE text", row.tablename))
129                                                sql.execute(sprintf("ALTER TABLE %s ALTER COLUMN template_text_fields_string TYPE text", row.tablename))
130
131                                        } catch (Exception e) {
132                                                println "changeTemplateTextFieldSignatures database upgrade failed: " + e.getMessage()
133                                        }
134                                }
135                }
136        }
137
138        /**
139         * The fields 'notify' and 'openInFrame' have been added to AssayModule. However, there
140         * seems to be no method to setting the default values of these fields in the database. They
141         * are set to NULL by default, so all existing fields have 'NULL' set.
142         * This method sets the default values
143         * @param sql
144         * @param db
145         */
146        public static void setAssayModuleDefaultValues(sql, db) {
147                // do we need to perform this upgrade?
148                if ((db == "org.postgresql.Driver" || db == "com.mysql.jdbc.Driver") &&
149                        (sql.firstRow("SELECT * FROM assay_module WHERE notify IS NULL") || sql.firstRow("SELECT * FROM assay_module WHERE open_in_frame IS NULL"))
150                ) {
151                        if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: assay_module default values for boolean fields".grom()
152
153                        try {
154                                sql.execute("UPDATE assay_module SET notify=" + ((db == "org.postgresql.Driver") ? 'FALSE' : '0') + " WHERE notify IS NULL")
155                        } catch (Exception e) {
156                                println "setAssayModuleDefaultValues database upgrade failed, notify field couldn't be set to default value: " + e.getMessage()
157                        }
158
159                        // set open_in_frame?
160                        try {
161                                sql.execute("UPDATE assay_module SET open_in_frame=" + ((db == "org.postgresql.Driver") ? 'TRUE' : '1') + " WHERE open_in_frame IS NULL")
162                        } catch (Exception e) {
163                                // Maybe gdt plugin is not updated yet after revision 109 ?
164                                println "setAssayModuleDefaultValues database upgrade failed, openInFrame field couldn't be set to default value: " + e.getMessage()
165                        }
166                }
167        }
168
169        /**
170         * Drop the unique constraint for the "name" column in the MappingColumn domain
171         *
172         * @param sql
173         * @param db
174         */
175        public static void dropMappingColumnNameConstraint(sql, db) {
176                // are we running postgreSQL ?
177                if (db == "org.postgresql.Driver") {
178                        if (sql.firstRow("SELECT * FROM pg_constraint WHERE contype='mapping_column_name_key'")) {
179                                if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: mapping column name constraint".grom()
180                                try {
181                                        // Check if constraint still exists
182                                        sql.execute("ALTER TABLE mapping_column DROP CONSTRAINT mapping_column_name_key")
183                                } catch (Exception e) {
184                                        println "dropMappingColumnNameConstraint database upgrade failed, `name` field unique constraint couldn't be dropped: " + e.getMessage()
185                                }
186                        }
187                }
188        }
189
190        /**
191         * the importer requires the value field to be nullable
192         * @param sql
193         * @param db
194         */
195        public static void makeMappingColumnValueNullable(sql, db) {
196                // are we running postgreSQL?
197                if (db == "org.postgresql.Driver") {
198                        // do we need to perform this update?
199                        if (sql.firstRow("SELECT * FROM information_schema.columns WHERE columns.table_name='mapping_column' AND columns.column_name='value' AND is_nullable='NO'")) {
200                                if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: making mapping_column::value nullable".grom()
201
202                                try {
203                                        sql.execute("ALTER TABLE mapping_column ALTER COLUMN value DROP NOT NULL")
204                                } catch (Exception e) {
205                                        println "makeMappingColumnValueNullable database upgrade failed: " + e.getMessage()
206                                }
207                        }
208                }
209        }
210
211        /**
212         * The field study.code has been set to be nullable
213         * The field assay.externalAssayId has been removed
214         * @param sql
215         * @param db
216         */
217        public static void alterStudyAndAssay(sql, db) {
218                def updated = false
219
220                // are we running postgreSQL ?
221                if (db == "org.postgresql.Driver") {
222                        // see if table assay contains a column external_assayid
223                        if (sql.firstRow("SELECT * FROM information_schema.columns WHERE columns.table_name='assay' AND columns.column_name='external_assayid'")) {
224                                if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: dropping column 'external_assayid' from table 'assay'".grom()
225
226                                try {
227                                        sql.execute("ALTER TABLE assay DROP COLUMN external_assayid")
228                                        updated = true
229                                } catch (Exception e) {
230                                        println "alterStudyAndAssay database upgrade failed, externalAssayId could not be removed from assay: " + e.getMessage()
231                                }
232
233                        }
234
235                        // see if table study contains a column code which is not nullable
236                        if (sql.firstRow("SELECT * FROM information_schema.columns WHERE columns.table_name='study' AND columns.column_name='code' AND is_nullable='NO'")) {
237                                if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: dropping column 'code' from table 'study'".grom()
238
239                                try {
240                                        sql.execute("ALTER TABLE study ALTER COLUMN code DROP NOT NULL")
241                                        updated = true
242                                } catch (Exception e) {
243                                        println "alterStudyAndAssay database upgrade failed, study.code could not be set to accept null values: " + e.getMessage()
244                                }
245                        }
246
247                        // Load all studies and save them again. This prevents errors on saving later
248                        if (updated) {
249                                if (String.metaClass.getMetaMethod("grom")) "re-saving studies...".grom()
250
251                                Study.list().each { study ->
252                                        if (String.metaClass.getMetaMethod("grom")) "re-saving study: ${study}".grom()
253                                        study.save()
254                                }
255                        }
256                }
257        }
258
259        /**
260         * make sure all date_created and last_updated columns are NOT nullable, and
261         * set values to now() of they are null
262         * @param sql
263         * @param db
264         */
265        public static void fixDateCreatedAndLastUpdated(sql, db) {
266                // are we running PostgreSQL?
267                if (db == "org.postgresql.Driver") {
268                        // see if we need to modify anything?
269                        sql.eachRow("SELECT table_name,column_name FROM information_schema.columns WHERE column_name IN ('last_updated', 'date_created') AND is_nullable='YES'") { row ->
270                                // grom what we are doing
271                                if (String.metaClass.getMetaMethod("grom")) "fixing nullable for ${row.table_name}:${row.column_name}".grom()
272
273                                // fix database
274                                try {
275                                        // setting all null values to now()
276                                        sql.execute(sprintf("UPDATE %s SET %s=now() WHERE %s IS NULL",row.table_name,row.column_name,row.column_name))
277
278                                        // and alter the table to disallow null values
279                                        sql.execute(sprintf("ALTER TABLE %s ALTER COLUMN %s SET NOT NULL",row.table_name,row.column_name))
280                                } catch (Exception e) {
281                                        println "fixDateCreatedAndLastUpdated database upgrade failed: " + e.getMessage()
282                                }
283                        }
284                }
285        }
286       
287       
288        /**
289         * drops the field platform from assay modules
290         * @param sql
291         * @param db
292         */
293        public static void dropAssayModulePlatform(sql, db) {
294                // are we running postgreSQL?
295                if (db == "org.postgresql.Driver") {
296                        // do we need to perform this update?
297                        if (sql.firstRow("SELECT * FROM information_schema.columns WHERE columns.table_name='assay_module' AND columns.column_name='platform'")) {
298                                if (String.metaClass.getMetaMethod("grom")) "performing database upgrade: removing assayModule platform".grom()
299
300                                try {
301                                        sql.execute("ALTER TABLE assay_module DROP COLUMN platform")
302                                } catch (Exception e) {
303                                        println "dropAssayModulePlatform database upgrade failed: " + e.getMessage()
304                                }
305                        }
306                }
307        }
308}
Note: See TracBrowser for help on using the browser.