source: trunk/grails-app/services/nl/tno/metagenomics/SampleExcelService.groovy @ 7

Last change on this file since 7 was 7, checked in by robert@…, 8 years ago
  • Created tests for the synchronization and trash
  • Improved synchronizationservice and trash
  • Put authorization checks in several pages
File size: 6.0 KB
Line 
1package nl.tno.metagenomics
2
3class SampleExcelService {
4        def excelService
5        def fuzzySearchService
6       
7    static transactional = true
8
9        // Fields to be edited using excel file and manually
10        def sampleNameName = "Sample name"
11        def runName = "Run"
12        def tagSequenceName = "Tag sequence"
13        def oligoNumberName = "Oligo number"
14        def possibleFields = [sampleNameName, runName, tagSequenceName, oligoNumberName]
15       
16    def downloadSampleExcel( def assaySamples, boolean includeRun = true ) {
17                def sheetIndex = 0;
18               
19                if( assaySamples == null )
20                        assaySamples = []
21                       
22                def sortedSamples = assaySamples.toList().sort { it.sample.name }
23               
24                // Create an excel sheet
25                def wb = excelService.create();
26
27                def fields = possibleFields
28                if( !includeRun )
29                        fields = fields - runName
30               
31                // Put the headers on the first row
32                excelService.writeHeader( wb, fields, sheetIndex );
33
34                // Adding the next lines
35                ArrayList data = [];
36                sortedSamples.each { assaySample ->
37                        def rowData = [assaySample.sample?.name];
38                        if( includeRun )
39                                rowData << assaySample.run?.name
40                       
41                        rowData << assaySample.tagSequence
42                        rowData << assaySample.oligoNumber
43                        data << rowData;
44                }
45                excelService.writeData( wb, data, sheetIndex, 1 );
46
47                // Auto resize columns
48                excelService.autoSizeColumns( wb, sheetIndex, 0..2)
49
50                return wb;             
51    }
52       
53        def parseTagsExcel( File file, boolean includeRun = true ) {
54                def sheetIndex = 0
55                def headerRow = 0
56                def dataStartsAtRow = 1
57                def numExampleRows = 5
58               
59                // Create an excel workbook instance of the file
60                def     workbook = excelService.open( file );
61
62                // Read headers from the first row and 5 of the first lines as example data
63                def headers = excelService.readRow( workbook, sheetIndex, headerRow );
64                def exampleData = excelService.readData( workbook, sheetIndex, dataStartsAtRow, -1, numExampleRows ); // -1 means: determine number of rows yourself
65
66                // Try to guess best matches between the excel file and the column names
67                def bestMatches = [:]
68                def fields = possibleFields
69                if( !includeRun )
70                        fields = fields - runName
71                       
72                headers.eachWithIndex { header, idx ->
73                        // Do matching using fuzzy search. The 0.1 treshold makes sure that no match if chosen if
74                        // there is actually no match at all.
75                        bestMatches[idx] = fuzzySearchService.mostSimilar( header, possibleFields, 0.1 );
76                }
77               
78                return [headers: headers, exampleData: exampleData, bestMatches: bestMatches, possibleFields: fields]
79        }
80       
81        def updateTagsByExcel( def matchColumns, def possibleFields, File file, def assaySamples ) {
82                def sheetIndex = 0
83                def headerRow = 0
84                def dataStartsAtRow = 1
85
86                if( !matchColumns ) {
87                        // Now delete the file, since we don't need it anymore
88                        file?.delete()
89
90                        return [ success: false, message: "No column matches found for excel file. Please try again." ]
91                }
92
93                // Determine column numbers
94                def columns = [:]
95                def dataMatches = false;
96                possibleFields.each { columnName ->
97                        columns[ columnName ] = matchColumns.findIndexOf { it.value == columnName }
98
99                        if( columnName != sampleNameName && columns[ columnName ] != -1 )
100                                dataMatches = true
101                }
102
103                // A column to match the sample name must be present
104                if( columns[ sampleNameName ] == -1 ) {
105                        // Now delete the file, since we don't need it anymore
106                        _deleteUploadedFileFromSession()
107
108                        return [ success: false, message: "There must be a column present in the excel file that matches the sample name. Please try again." ]
109                }
110
111                // A column with data should also be present
112                if( !dataMatches ) {
113                        // Now delete the file, since we don't need it anymore
114                        _deleteUploadedFileFromSession()
115
116                        return [ success: false, message: "There are no data columns present in the excel file. No samples are updated." ]
117                }
118
119                // Now loop through the excel sheet and update all samples with the specified data
120                if( !file.exists() || !file.canRead() ) {
121                        return [ success: false, message: "Excel file has been removed since previous step. Please try again." ]
122                }
123
124                def workbook = excelService.open( file )
125                ArrayList data = excelService.readData( workbook, sheetIndex, dataStartsAtRow )
126
127                // Check whether the excel file contains any data
128                if( data.size() == 0 ) {
129                        // Now delete the file, since we don't need it anymore
130                        file.delete()
131
132                        return [ success: false, message: "The excel sheet contains no data to import. Please upload another excel file." ]
133                }
134
135                def numSuccesful = 0
136                def failedRows = []
137
138                // walk through all rows and fill the table with records
139                for( def i = 0; i < data.size(); i++ ) {
140                        def rowData = data[ i ];
141
142                        String sampleName = rowData[ columns[ sampleNameName ] ] as String
143
144                        // Find assay by sample name. Since sample names are unique within an assay (enforced by GSCF),
145                        // this will always work when only using one assay. When multiple assays are used, this might pose
146                        // a problem
147                        AssaySample assaySample = assaySamples.find { it.sample.id == Sample.findByName( sampleName )?.id };
148
149                        // If no assaysample is found, add this row to the failed-row list
150                        if( !assaySample ) {
151                                failedRows << [ row: rowData, sampleName: sampleName ];
152                                continue;
153                        }
154
155                        columns.each {
156                                if( it.value > -1 ) {
157                                        switch( it.key ) {
158                                                case tagSequenceName:   assaySample.tagSequence = rowData[ it.value ]; break
159                                                case oligoNumberName:   assaySample.oligoNumber = rowData[ it.value ]; break
160                                                case runName:                   assaySample.run = Run.findByName( rowData[ it.value ] ); break
161                                        }
162                                }
163                        }
164
165                        assaySample.save()
166
167                        numSuccesful++;
168                }
169
170                // Now delete the file, since we don't need it anymore
171                file.delete()
172
173                // Return a message to the user
174                if( numSuccesful == 0 ) {
175                        return [success: false, message: "None of the " + failedRows.size() + " row(s) could be imported, because none of the sample names matched. Have you provided the right excel file?" ]
176                } else {
177                        def message = numSuccesful + " samples have been updated. "
178
179                        if( failedRows.size() > 0 )
180                                message += failedRows.size() + " row(s) could not be imported, because the sample names could not be found in the database."
181
182                        return [success: true, message: message, numSuccesful: numSuccesful, failedRows: failedRows ]
183
184                }
185        }
186}
Note: See TracBrowser for help on using the repository browser.