source: trunk/grails-app/domain/dbnp/studycapturing/Study.groovy @ 813

Last change on this file since 813 was 813, checked in by keesvb, 10 years ago

updated event group with unique name constraint, added EventGroup? tests and updated deleteEventGroup to deal with empty event groups

  • Property svn:keywords set to Author Rev Date
File size: 9.5 KB
Line 
1package dbnp.studycapturing
2
3import dbnp.user.User
4
5/**
6 * Domain class describing the basic entity in the study capture part: the Study class.
7 *
8 * Revision information:
9 * $Rev: 813 $
10 * $Author: keesvb $
11 * $Date: 2010-08-16 16:27:31 +0000 (ma, 16 aug 2010) $
12 */
13class Study extends TemplateEntity {
14        static searchable = {
15        [only: ['title', 'Description']]
16    }
17
18        User owner   // The owner of the study. A new study is automatically owned by its creator.
19        String title        // The title of the study
20        String code             // currently used as the external study ID, e.g. to reference a study in a SAM module
21        Date dateCreated
22        Date lastUpdated
23        Date startDate
24    List subjects
25        List events
26        List samplingEvents
27        List eventGroups
28        List samples
29        List assays
30
31        static hasMany = [
32                editors: User,   // Users with read/write access to the study
33                readers: User,   // Users with only read access to the study
34                subjects: Subject,
35                samplingEvents: SamplingEvent,
36                events: Event,
37                eventGroups: EventGroup,
38                samples: Sample,
39                assays: Assay,
40                persons: StudyPerson,
41                publications: Publication
42        ]
43
44        static constraints = {
45                owner(nullable: true, blank: true)
46                code(nullable:false, blank:true,unique:true) 
47        }
48
49        static mapping = {
50                researchQuestion type: 'text'
51                description type: 'text'
52                autoTimestamp true
53        }
54
55        // The external study ID is currently defined as the code of the study.
56        // It is used from within dbNP submodules to refer to particular study in this GSCF instance.
57        def getExternalStudyId() { code }
58
59        /**
60         * return the domain fields for this domain class
61         * @return List
62         */
63        static List<TemplateField> giveDomainFields() { return Study.domainFields }
64
65        static final List<TemplateField> domainFields = [
66                new TemplateField(
67                        name: 'title',
68                        type: TemplateFieldType.STRING),
69                new TemplateField(
70                        name: 'code',
71                        type: TemplateFieldType.STRING,
72                        preferredIdentifier:true,
73                        comment: 'Fill out the code by which many people will recognize your study'),
74                new TemplateField(
75                        name: 'startDate',
76                        type: TemplateFieldType.DATE,
77                        comment: 'Fill out the official start date or date of first action')
78        ]
79
80        /**
81         * return the title of this study
82         */
83        def String toString() {
84                return title
85        }
86
87        /**
88         * returns all events and sampling events that do not belong to a group
89         */
90        def Set<Event> getOrphanEvents() {
91                def orphans =   events.findAll { event -> !event.belongsToGroup(eventGroups) } +
92                                                samplingEvents.findAll { event -> !event.belongsToGroup(eventGroups) }
93
94                return orphans
95        }
96
97        /**
98         * Return the unique Subject templates that are used in this study
99         */
100        def Set<Template> giveSubjectTemplates() {
101                TemplateEntity.giveTemplates(subjects)
102        }
103
104        /**
105         * Return all subjects for a specific template
106         * @param Template
107         * @return ArrayList
108         */
109        def ArrayList<Subject> giveSubjectsForTemplate(Template template) {
110                subjects.findAll { it.template.equals(template) }
111        }
112
113        /**
114         * Return the unique Event and SamplingEvent templates that are used in this study
115         */
116        Set<Template> giveAllEventTemplates() {
117                // For some reason, giveAllEventTemplates() + giveAllSamplingEventTemplates()
118                // gives trouble when asking .size() to the result
119                // So we also use giveTemplates here
120                TemplateEntity.giveTemplates( ((events) ? events : []) + ((samplingEvents) ? samplingEvents : []) )
121        }
122
123
124        /**
125         * Return all events and samplingEvenets for a specific template
126         * @param Template
127         * @return ArrayList
128         */
129        def ArrayList giveEventsForTemplate(Template template) {
130                def events = events.findAll { it.template.equals(template) }
131                def samplingEvents = samplingEvents.findAll { it.template.equals(template) }
132
133                return (events) ? events : samplingEvents
134        }
135
136        /**
137         * Return the unique Event templates that are used in this study
138         */
139        Set<Template> giveEventTemplates() {
140                TemplateEntity.giveTemplates(events)
141        }
142
143        /**
144         * Return the unique SamplingEvent templates that are used in this study
145         */
146        Set<Template> giveSamplingEventTemplates() {
147                TemplateEntity.giveTemplates(samplingEvents)
148        }
149
150        /**
151         * Returns the unique Sample templates that are used in the study
152         */
153        Set<Template> giveSampleTemplates() {
154                TemplateEntity.giveTemplates(samples)
155        }
156
157        /**
158         * Return all samples for a specific template
159         * @param Template
160         * @return ArrayList
161         */
162        def ArrayList<Subject> giveSamplesForTemplate(Template template) {
163                samples.findAll { it.template.equals(template) }
164        }
165
166        /**
167         * Returns the template of the study
168         */
169        Template giveStudyTemplate() {
170                return this.template
171        }
172
173
174        /**
175         * Delete a specific subject from this study, including all its relations
176         * @param subject The subject to be deleted
177         * @return A String which contains a (user-readable) message describing the changes to the database
178         */
179        String deleteSubject(Subject subject) {
180                String msg = "Subject ${subject.name} was deleted"
181
182                // Delete the subject from the event groups it was referenced in
183                this.eventGroups.each {
184                        if (it.subjects.contains(subject)) {
185                                it.removeFromSubjects(subject)
186                                msg += ", deleted from event group '${it.name}'"
187                        }
188                }
189
190                // Delete the samples that have this subject as parent
191                this.samples.findAll { it.parentSubject.equals(subject) }.each {
192                        // This should remove the sample itself too, because of the cascading belongsTo relation
193                        this.removeFromSamples(it)
194                        // But apparently it needs an explicit delete() too
195                        it.delete()
196                        msg += ", sample '${it.name}' was deleted"
197                }
198
199                // This should remove the subject itself too, because of the cascading belongsTo relation
200                this.removeFromSubjects(subject)
201                // But apparently it needs an explicit delete() too
202                subject.delete()
203
204                return msg
205        }
206
207        /**
208         * Delete an event from the study, including all its relations
209         * @param Event
210         * @return String
211         */
212        String deleteEvent(Event event) {
213                String msg = "Event ${event} was deleted"
214
215                // remove event from the study
216                this.removeFromEvents(event)
217
218                // remove event from eventGroups
219                this.eventGroups.each() { eventGroup ->
220                        eventGroup.removeFromEvents(event)
221                }
222
223                return msg
224        }
225
226        /**
227         * Delete a samplingEvent from the study, including all its relations
228         * @param SamplingEvent
229         * @return String
230         */
231        String deleteSamplingEvent(SamplingEvent samplingEvent) {
232                String msg = "SamplingEvent ${samplingEvent} was deleted"
233
234                // remove event from eventGroups
235                this.eventGroups.each() { eventGroup ->
236                        eventGroup.removeFromSamplingEvents(samplingEvent)
237                }
238
239                // Delete the samples that have this sampling event as parent
240                this.samples.findAll { it.parentEvent.equals(samplingEvent) }.each {
241                        // This should remove the sample itself too, because of the cascading belongsTo relation
242                        this.removeFromSamples(it)
243                        // But apparently it needs an explicit delete() too
244                        it.delete()
245                        msg += ", sample '${it.name}' was deleted"
246                }
247
248                // Remove event from the study
249                // This should remove the event group itself too, because of the cascading belongsTo relation
250                this.removeFromSamplingEvents(samplingEvent)
251                // But apparently it needs an explicit delete() too
252                // (Which can be verified by outcommenting this line, then SampleTests.testDeleteViaParentSamplingEvent fails
253                samplingEvent.delete()
254
255                return msg
256        }
257       
258        /**
259         * Delete an eventGroup from the study, including all its relations
260         * @param EventGroup
261         * @return String
262         */
263        String deleteEventGroup(EventGroup eventGroup) {
264                // TODO THIS DOESNT WORK!!!!
265                println "-"
266                println "-"
267                println "-"
268                println "-"
269                println "-"
270                println "REMOVING AN EVENTGROUP DOES NOT DELETE SAMPLES"
271                println "-"
272                println "-"
273                println "-"
274                println "-"
275                println "-"
276
277
278
279                String msg = "EventGroup ${eventGroup} was deleted"
280
281                // If the event group contains sampling events
282                if (eventGroup.samplingEvents) {
283                        // remove all samples that originate from this eventGroup
284                        if (eventGroup.samplingEvents.size()) {
285                                // find all samples related to this eventGroup
286                                // - subject comparison is relatively straightforward and
287                                //   behaves as expected
288                                // - event comparison behaves strange, so now we compare
289                                //              1. database id's or,
290                                //              2. object identifiers or,
291                                //              3. objects itself
292                                //   this seems now to work as expected
293                                this.samples.findAll { sample ->
294                                        (
295                                                (eventGroup.subjects.findAll {
296                                                        it.equals(sample.parentSubject)
297                                                })
298                                                &&
299                                                (eventGroup.samplingEvents.findAll {
300                                                        (
301                                                                (it.id && sample.parentEvent.id && it.id==sample.parentEvent.id)
302                                                                ||
303                                                                (it.getIdentifier() == sample.parentEvent.getIdentifier())
304                                                                ||
305                                                                it.equals(sample.parentEvent)
306                                                        )
307                                                })
308                                        )
309                                }.each() {
310                                        // remove sample from study
311
312                                        // -------
313                                        // NOTE, the right samples are found, but the don't
314                                        // get deleted from the database!
315                                        // -------
316
317                                        println ".removing sample '${it.name}' from study '${this.title}'"
318                                        msg += ", sample '${it.name}' was deleted"
319                                        this.removeFromSamples( it )
320                                }
321                        }
322
323                        // remove all samplingEvents from this eventGroup
324                        eventGroup.samplingEvents.findAll{}.each() {
325                                eventGroup.removeFromSamplingEvents(it)
326                                println ".removed samplingEvent '${it.name}' from eventGroup '${eventGroup.name}'"
327                                msg += ", samplingEvent '${it.name}' was removed from eventGroup '${eventGroup.name}'"
328                        }
329                }
330
331                // If the event group contains subjects
332                if (eventGroup.subjects) {
333                        // remove all subject from this eventGroup
334                        eventGroup.subjects.findAll{}.each() {
335                                eventGroup.removeFromSubjects(it)
336                                println ".removed subject '${it.name}' from eventGroup '${eventGroup.name}'"
337                                msg += ", subject '${it.name}' was removed from eventGroup '${eventGroup.name}'"
338                        }
339                }
340
341                // remove the eventGroup from the study
342                println ".remove eventGroup '${eventGroup.name}' from study '${this.title}'"
343                this.removeFromEventGroups(eventGroup)
344
345                return msg
346        }
347}
Note: See TracBrowser for help on using the repository browser.