root/trunk/grails-app/domain/dbnp/studycapturing/Sample.groovy @ 1588

Revision 1588, 4.8 KB (checked in by s.h.sikkema@…, 3 years ago)

Fixed tests (except webtests); cleaned up Example{Studies,Templates}.groovy; decapitalized injected services; made 'transactional' properties static

  • Property svn:keywords set to Rev Author Date
Line 
1package dbnp.studycapturing
2import org.dbnp.gdt.*
3
4/**
5 * The Sample class describes an actual sample which results from a SamplingEvent.
6 *
7 * Revision information:
8 * $Rev$
9 * $Author$
10 * $Date$
11 */
12class Sample extends TemplateEntity {
13        // uncommented due to searchable issue
14        // @see http://jira.codehaus.org/browse/GRAILSPLUGINS-1577
15        //static searchable = { [only: ['name']] }
16
17        static belongsTo = [
18                // A Sample always belongs to one study.
19                parent                  : Study,
20
21                // A Sample optionally has a parent Subject from which it was taken, this Subject should be in the same parent study.
22                parentSubject   : Subject,
23
24                // Also, it has a parent SamplingEvent describing the actual sampling, also within the same parent study.
25                parentEvent             : SamplingEvent,
26
27                // And it has a parent EventGroup which tied it to its parent subject and parent event
28                parentEventGroup: EventGroup
29
30                // We can't have parentAssay since a Sample can belong to multiple Assays
31        ]
32
33        String name             // should be unique with respect to the parent study (which can be inferred)
34        Term material           // material of the sample (should normally be bound to the BRENDA ontology)
35       
36        /**
37         * UUID of this sample
38         */
39        String sampleUUID
40       
41        /**
42         * return the domain fields for this domain class
43         * @return List
44         */
45        static List<TemplateField> giveDomainFields() { return Sample.domainFields }
46
47        // We have to specify an ontology list for the material property. However, at compile time, this ontology does of course not exist.
48        // Therefore, the ontology is added at runtime in the bootstrap, possibly downloading the ontology properties if it is not present in the database yet.
49        static List<TemplateField> domainFields = [
50                new TemplateField(
51                        name: 'name',
52                        type: TemplateFieldType.STRING,
53                        preferredIdentifier: true,
54                        required: true
55                ),
56                new TemplateField(
57                        name: 'material',
58                        type: TemplateFieldType.ONTOLOGYTERM,
59                        comment: "The material is based on the BRENDA tissue / enzyme source ontology, a structured controlled vocabulary for the source of an enzyme. It comprises terms for tissues, cell lines, cell types and cell cultures from uni- and multicellular organisms. If a material is missing, please add it by using 'add more'"
60                )
61        ]
62
63        static constraints = {
64                // The parent subject is optional, e.g. in a biobank of samples the subject could be unknown or non-existing.
65                parentSubject(nullable:true)
66
67                // The same holds for parentEvent
68                parentEvent(nullable:true)
69
70                // and for parentEventGroup
71                parentEventGroup(nullable:true)
72
73                // The material domain field is optional
74                material(nullable: true)
75
76                sampleUUID(nullable: true, unique: true)
77
78                // Check if the externalSampleId (currently defined as name) is really unique within each parent study of this sample.
79                // This feature is tested by integration test SampleTests.testSampleUniqueNameConstraint
80                name(unique:['parent'])
81
82                // Same, but also when the other sample is not even in the database
83                // This feature is tested by integration test SampleTests.testSampleUniqueNameConstraintAtValidate
84                name(validator: { field, obj, errors ->
85                        // 'obj' refers to the actual Sample object
86
87                        // define a boolean
88                        def error = false
89
90                        // check whether obj.parent.samples is not null at this stage to avoid null pointer exception
91                        if (obj.parent) {
92
93                                if (obj.parent.samples) {
94
95                                        // check if there is exactly one sample with this name in the study (this one)
96                                        if (obj.parent.samples.findAll{ it.name == obj.name}.size() > 1) {
97                                                error = true
98                                                errors.rejectValue(
99                                                        'name',
100                                                        'sample.UniqueNameViolation',
101                                                        [obj.name, obj.parent] as Object[],
102                                                        'Sample name {0} appears multiple times in study {1}'
103                                                        )
104                                        }
105                                }
106                        }
107                        else {
108                                // if there is no parent study defined, fail immediately
109                                error = true
110                        }
111
112                        // got an error, or not?
113                        return (!error)
114                })
115        }
116
117    static mapping = {
118        sort "name"
119
120        // Workaround for bug http://jira.codehaus.org/browse/GRAILS-6754
121        templateTextFields type: 'text'
122    }
123
124        static getSamplesFor( event ) {
125                return  Sample.findAll( 'from Sample s where s.parentEvent =:event', [event:event] )
126        }
127
128        def String toString() {
129                return name
130        }
131
132        /**
133        * Basic equals method to check whether objects are equals, by comparing the ids
134        * @param o              Object to compare with
135        * @return               True iff the id of the given Sample is equal to the id of this Sample
136        */
137   public boolean equals( Object o ) {
138           if( o == null )
139                   return false;
140                   
141           if( !( o instanceof Sample ) )
142                   return false
143           
144           Sample s = (Sample) o;
145           
146           return this.id == s.id
147   }
148       
149        /**
150         * Returns the UUID of this sample and generates one if needed
151         */
152        public String giveUUID() {
153                if( !this.sampleUUID ) {
154                        this.sampleUUID = UUID.randomUUID().toString();
155                        if( !this.save(flush:true) ) {
156                                log.error "Couldn't save sample UUID: " + this.getErrors();
157                        }
158                }
159               
160                return this.sampleUUID;
161        }
162}
Note: See TracBrowser for help on using the browser.