source: trunk/grails-app/domain/dbnp/studycapturing/Sample.groovy @ 1488

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