source: trunk/grails-app/services/nl/tno/massSequencing/integration/TrashService.groovy @ 65

Last change on this file since 65 was 65, checked in by robert@…, 8 years ago

Fixed problems with number of sequences after trashing samples

File size: 13.0 KB
Line 
1package nl.tno.massSequencing.integration
2
3import nl.tno.massSequencing.*
4import nl.tno.massSequencing.auth.Auth;
5
6
7class TrashService {
8
9        static transactional = true
10
11        /**
12         * Moves the valuable data from a study to trash and deletes the study
13         * @param               Study to move to trash
14         */
15        def moveToTrash( Study study ) {
16                log.trace "Moving study " + study + " to trash";
17                if( study.trashcan )
18                        return
19
20                saveDataInTrash( study );
21               
22                def l = []
23                if( study.auth ) {
24                        l += study.auth
25                       
26                        l.each { auth ->
27                                auth.user?.removeFromAuth( auth );
28                                study.removeFromAuth( auth );
29                        }
30                }
31               
32                // Remove sequence data first, since it gives problems when keeping it
33                if( study.assays ) { 
34                        l = [] + study.assays*.assaySamples*.sequenceData?.flatten()
35                       
36                        l.each { 
37                                if( it )
38                                        it.sample.removeFromSequenceData( it );
39                        }
40                }
41                study.delete(flush:true);
42        }
43
44        /**
45         * Moves the valuable data from an assay to trash and deletes the assay
46         * @param               Assay to move to trash
47         */
48        def moveToTrash( Assay assay ) {
49                saveDataInTrash( assay );
50
51                // Remove associations
52                def l = []
53                if( assay.runs ) {
54                        l += assay.runs
55                       
56                        l.each {
57                                if( it ) {
58                                        assay.removeFromRuns( it );
59                                        it.removeFromAssays( assay );
60                                }
61                        }
62                }
63               
64                if( assay.assaySamples ) {
65                        // Remove sequence data first, since it gives problems when keeping it
66                        l = [] + assay.assaySamples*.sequenceData?.flatten()
67                       
68                        l.each {
69                                if( it ) {
70                                        it.sample.removeFromSequenceData( it );
71                                }
72                        }
73                       
74                        l = [] + assay.assaySamples
75                       
76                        l.each {
77                                it.sample.removeFromAssaySamples( it );
78                                assay.removeFromAssaySamples( it );
79                        }
80                }
81
82
83               
84                def study = assay.study
85                if( study ) {
86                        study.removeFromAssays( assay );
87                }
88        }
89
90        /**
91         * Moves the valuable data from a sample to trash and deletes the sample
92         * @param               Sample to move to trash
93         */
94        def moveToTrash( Sample sample ) {
95                saveDataInTrash( sample );
96
97                // Remove associations
98                def l = []
99                if( sample.assaySamples ) {
100                        // Remove sequence data first, since it gives problems when keeping it
101                        l = [] + sample.assaySamples*.sequenceData?.flatten()
102                       
103                        l.each {
104                                if( it ) {
105                                        it.sample.removeFromSequenceData( it );
106                                }
107                        }
108                       
109                        l =[] + sample.assaySamples
110                       
111                        l.each {
112                                it.assay.removeFromAssaySamples( it );
113                                sample.removeFromAssaySamples( it );
114                        }
115                }
116               
117                def study = sample.study
118                sample.study.removeFromSamples( sample );
119                study.save();
120        }
121
122        /**
123        * Moves the valuable data from an assaySample to trash and deletes the assay
124        * @param                Assay to move to trash
125        */
126   def moveToTrash( AssaySample assaySample ) {
127           saveDataInTrash( assaySample );
128
129           // Remove associations
130           if( assaySample.run ) {
131                   assaySample.run.removeFromAssaySamples( assaySample );
132           }
133           
134           if( assaySample.assay ) {
135                   assaySample.assay.removeFromAssaySamples( assaySample );
136           }
137
138           if( assaySample.sample ) {
139                   assaySample.sample.removeFromAssaySamples( assaySample );
140           }
141           
142           def l = []
143           if( assaySample.sequenceData ) {
144                   l += assaySample.sequenceData
145                   
146                   l.each {
147                           if( it ) {
148                                        assaySample.removeFromSequenceData( it );
149                           }
150                   }
151           }
152           
153   }
154       
155        /**
156         * Saves data from the study in the trash can (if any data exists)
157         * @param study         Study to save data from
158         * @return
159         */
160        def saveDataInTrash( Study study ) {
161                Study trashcan = this.giveTrashcan()
162
163                if( !trashcan ) {
164                        log.warn "No trashcan (study with trashcan property set to true) found in the database when deleting study " + study.name + ". Possibly valuable data is deleted forever."
165                        return;
166                }
167
168                // Loop through all assays, and see if there are assay samples
169                // that have data
170                study.assays.each { assay ->
171                        saveDataInTrash( assay );
172                }
173        }
174
175        /**
176         * Saves data from the assay in the trash can (if any data exists)
177         * @param study         Assay to save data from
178         * @return
179         */
180        def saveDataInTrash( Assay assay ) {
181                Study trashcan = this.giveTrashcan()
182
183                if( !trashcan ) {
184                        log.warn "No trashcan (study with trashcan property set to true) found in the database when deleting assay " + assay.name + ". Possibly valuable data is deleted forever."
185                        return;
186                }
187
188                def assaySamples = assay.assaySamples.findAll { it.containsData() }
189
190                // For every assay sample that contains data, save that data in the trashcan
191                if( assaySamples.size() > 0 ) {
192                        // Create a dummy assay copy of the existing assay
193                        String newAssayToken = 'TrashAssay ' + new Date().format( 'yyyyMMddHHmmssSSS') + ( Math.random() * 10000 );
194
195                        Assay dummyAssay = new Assay( assayToken: newAssayToken, name: assay.name, study: trashcan );
196                        trashcan.addToAssays( dummyAssay );
197                        dummyAssay.save()
198
199                        assaySamples.each { assaySample ->
200                                Sample sample = assaySample.sample
201
202                                // Create dummy sample
203                                String newSampleToken = 'TrashSample ' + new Date().format( 'yyyyMMddHHmmssSSS') + ( Math.random() * 10000 );
204                                Sample dummySample = Sample.cloneSample( sample, newSampleToken, trashcan );
205                                trashcan.addToSamples( dummySample );
206                                dummySample.save()
207
208                                // Create dummy assay sample
209                                AssaySample dummyAssaySample = new AssaySample( assay: dummyAssay, sample: dummySample, numSequences: assaySample.numSequences );
210
211                                dummyAssay.addToAssaySamples( dummyAssaySample );
212                                dummySample.addToAssaySamples( dummyAssaySample );
213                                dummyAssaySample.save();
214
215                                // Move data from this assay sample to the trash version of it
216                                assaySample.moveValuableDataTo( dummyAssaySample );
217                               
218                                // Remove the assaySample from its run, since otherwise the statistics of the run (#sequences for example)
219                                // are not correct anymore and the assaySample will be resaved after delete
220                                dummyAssaySample.run?.removeFromAssaySamples( dummyAssaySample );
221                               
222                                dummyAssaySample.save();
223                        }
224                }
225               
226                // Remove all assaysamples from this assay from their run
227                assay.assaySamples?.each { assaySample ->
228                        assaySample.run?.removeFromAssaySamples( assaySample );
229                }
230               
231                // Remove this assay from the runs, since otherwise the samples will be resaved upon delete
232                if( assay.runs ) {
233                        def l = [] + assay.runs
234                        l.each {
235                                it.removeFromAssays( assay );
236                        }
237                }
238        }
239
240        /**
241         * Saves data from the sample in the trash can (if any data exists)
242         * @param study         Sample to save data from
243         * @return
244         */
245        def saveDataInTrash( Sample sample ) {
246                Study trashcan = this.giveTrashcan()
247
248                if( !trashcan ) {
249                        log.warn "No trashcan (study with trashcan property set to true) found in the database when deleting sample " + sample.name + ". Possibly valuable data is deleted forever."
250                        return;
251                }
252
253                def assaySamples = sample.assaySamples.findAll { it.containsData() }
254
255                // For every assay sample that contains data, save that data in the trashcan
256                if( assaySamples.size() > 0 ) {
257                        // Create dummy sample
258                        String newSampleToken = 'TrashSample ' + new Date().format( 'yyyyMMddHHmmssSSS') + ( Math.random() * 10000 );
259                        Sample dummySample = Sample.cloneSample( sample, newSampleToken, trashcan );
260                        trashcan.addToSamples( dummySample );
261                        dummySample.save()
262
263                        assaySamples.each { assaySample ->
264                                Assay assay = assaySample.assay;
265
266                                // Create a dummy assay copy of the existing assay
267                                String newAssayToken = 'TrashAssay ' + new Date().format( 'yyyyMMddHHmmssSSS') + ( Math.random() * 10000 );
268
269                                Assay dummyAssay = new Assay( assayToken: newAssayToken, name: assay.name, study: trashcan );
270                                trashcan.addToAssays( dummyAssay );
271                                dummyAssay.save()
272
273                                // Create dummy assay sample
274                                AssaySample dummyAssaySample = new AssaySample( assay: dummyAssay, sample: dummySample, numSequences: assaySample.numSequences );
275
276                                dummyAssay.addToAssaySamples( dummyAssaySample );
277                                dummySample.addToAssaySamples( dummyAssaySample );
278                                dummyAssaySample.save();
279
280                                // Move data from this assay sample to the trash version of it
281                                assaySample.moveValuableDataTo( dummyAssaySample );
282                               
283                                // Remove the assaySample from its run, since otherwise the statistics of the run (#sequences for example)
284                                // are not correct anymore
285                                dummyAssaySample.run?.removeFromAssaySamples( dummyAssaySample );
286
287                                dummyAssaySample.save();
288                        }
289                }
290               
291                // Remove all assaysamples from this assay from their run
292                sample.assaySamples?.each { assaySample ->
293                        assaySample.run?.removeFromAssaySamples( assaySample );
294                }
295        }
296
297       
298        /**
299        * Saves data from the assay-sample in the trash can (if any data exists)
300        * @param study          Sample to save data from
301        * @return
302        */
303   def saveDataInTrash( AssaySample assaySample ) {
304           Study trashcan = this.giveTrashcan()
305
306           if( !trashcan ) {
307                   log.warn "No trashcan (study with trashcan property set to true) found in the database when deleting sample " + sample.name + ". Possibly valuable data is deleted forever."
308                   return;
309           }
310
311           // For every assay sample that contains data, save that data in the trashcan
312           if( assaySample.containsData() ) {
313                   // Create dummy sample
314                   String newSampleToken = 'TrashSample ' + new Date().format( 'yyyyMMddHHmmssSSS') + ( Math.random() * 10000 );
315                   Sample dummySample = Sample.cloneSample( assaySample.sample, newSampleToken, trashcan );
316                   trashcan.addToSamples( dummySample );
317                   dummySample.save()
318
319                   Assay assay = assaySample.assay;
320
321                   // Create a dummy assay copy of the existing assay
322                   String newAssayToken = 'TrashAssay ' + new Date().format( 'yyyyMMddHHmmssSSS') + ( Math.random() * 10000 );
323
324                   Assay dummyAssay = new Assay( assayToken: newAssayToken, name: assay.name, study: trashcan );
325                   trashcan.addToAssays( dummyAssay );
326                   dummyAssay.save()
327
328                   // Create dummy assay sample
329                   AssaySample dummyAssaySample = new AssaySample( assay: dummyAssay, sample: dummySample, numSequences: assaySample.numSequences );
330
331                   dummyAssay.addToAssaySamples( dummyAssaySample );
332                   dummySample.addToAssaySamples( dummyAssaySample );
333                   dummyAssaySample.save();
334
335                   // Move data from this assay sample to the trash version of it
336                   assaySample.moveValuableDataTo( dummyAssaySample );
337                   dummyAssaySample.save();
338           }
339   }
340
341        /**
342         * Retrieves the trashcan study from the database
343         */
344        def giveTrashcan = {
345                def study = Study.findByTrashcan( true );
346
347                if( !study )
348                        return null;
349                else
350                        return study
351        }
352       
353        /**
354         * Creates a new trashcan study. Should only be used by the bootstrap to create a trashcan
355         */
356        def createTrashcan = {
357                def study = new Study( name: "Trashcan", studyToken: "trash", trashcan: true )
358                study.save();
359        }
360       
361        /**
362         * Sets up authorization for the trashcan study
363         */
364        def setupAuthorization = { study, admin ->
365                if( study && admin ) {
366                        def a = Auth.createAuth(study, admin);
367                        a.canRead = true;
368                        a.canWrite = true;
369                        a.isOwner = true;
370                        a.save();
371                }
372        }
373
374        /**
375         * Cleans up the trash by removing empty assays or samples. Empty means:
376         *      - an assay with samples
377         *  - a sample without sequences, tag sequence and oligo number
378         * 
379         *  Also removes samples in trash that are not referenced by an assaysample
380         */
381        def cleanTrash = {
382                def studies = Study.findAllByTrashcan( true );
383
384                studies.each { study ->
385                        def numAssays = study.assays?.size()
386                        def assayList = study.assays?.toList();
387
388                        def numSamples
389                        def sampleList
390
391                        // Loop backwards through the assays in order to facilitate removing assays
392                        for( def i = numAssays -1; i >= 0; i-- ) {
393                                // Loop through all samples and remove the ones that are empty
394                                if( assayList[ i ].assaySamples != null ) {
395                                        numSamples = assayList[ i ].assaySamples.size()
396                                        sampleList = assayList[ i ].assaySamples.toList();
397
398                                        for( def j = numSamples - 1; j >= 0; j-- ) {
399                                                def s = sampleList[ j ];
400                                                if( !s.containsData() ) {
401                                                        assayList[ i ].removeFromAssaySamples( s );
402                                                        s.sample?.delete();
403                                                        s.delete();
404                                                }
405                                        }
406                                }
407
408                                // Now check if there are samples left. Otherwise, remove the assay
409                                if( assayList[i].assaySamples == null || assayList[i].assaySamples.size() == 0 ) {
410                                        study.removeFromAssays( assayList[ i ] );
411                                        assayList[i].delete();
412                                }
413                        }
414
415                        // Loop through samples and delete the ones not referenced by an assaysample
416                        /*
417                         numSamples = study.samples?.size()
418                         sampleList = study.samples?.toList();
419                         for( def j = numSamples - 1; j >= 0; j-- ) {
420                         def s = sampleList[ j ];
421                         if( s.assaySamples == null || s.assaySamples.size() == 0 ) {
422                         study.removeFromSamples(s);
423                         s.delete(flush:true);
424                         }
425                         }
426                         */
427                }
428        }
429
430        /**
431         * Restore an assay from trash and put the contents of the assay in another assay
432         * @param assay
433         * @param restoreTo
434         */
435        public void restoreAssay( Assay assay, Assay restoreTo ) {
436                // Loop through all assaysamples and restore the ones that have a matching name
437                assay.assaySamples.each { assaySample ->
438                        if( assaySample ) {
439                                // Find a sample with the same name
440                                def restoreSample = restoreTo.assaySamples.find { it.sample?.name == assaySample.sample?.name }
441
442                                if( restoreSample ) {
443                                        this.restoreSample( assaySample, restoreSample );
444                                }
445                        }
446                }
447        }
448
449        /**
450         * Restore a sample from trash and put the contents of the sample into another sample
451         * @param sample
452         * @param restoreTo
453         */
454        public void restoreSample( AssaySample sample, AssaySample restoreTo ) {
455                sample.moveValuableDataTo( restoreTo );
456                restoreTo.save();
457        }
458}
Note: See TracBrowser for help on using the repository browser.