Changeset 754


Ignore:
Timestamp:
Jul 30, 2010, 3:05:41 PM (11 years ago)
Author:
keesvb
Message:

big refactoring / change of the data model: implemented belongsTo everywhere where it should be, added comments to the domain classes, changed BootStrap? accordingly

Location:
trunk/grails-app
Files:
1 deleted
23 edited

Legend:

Unmodified
Added
Removed
  • trunk/grails-app/conf/BootStrapStudies.groovy

    r703 r754  
    167167                        ecCode:"2007117.c",
    168168                        startDate: Date.parse('yyyy-MM-dd','2008-01-02'),
    169                 )
    170                 .with { if (!validate()) { errors.each { println it} } else save()}
     169                ).with { if (!validate()) { errors.each { println it} } else save()}
    171170
    172171                mouseStudy.setFieldValue('Description', "C57Bl/6 mice were fed a high fat (45 en%) or low fat (10 en%) diet after a four week run-in on low fat diet.");// After 1 week 10 mice that received a low fat diet were given an IP leptin challenge and 10 mice of the low-fat group received placebo injections. The same procedure was performed with mice that were fed the high-fat diet. After 4 weeks the procedure was repeated. In total 80 mice were culled." )
     
    179178                )
    180179                .setFieldValue( 'Diet','low fat')
    181                 .with { if (!validate()) { errors.each { println it} } else save()}
    182180
    183181                def evHF = new Event(
     
    187185                )
    188186                .setFieldValue( 'Diet','high fat' )
    189                 .with { if (!validate()) { errors.each { println it} } else save()}
    190187
    191188                def evBV = new Event(
     
    195192                )
    196193                .setFieldValue( 'Control','true' )
    197                 .with { if (!validate()) { errors.each { println it} } else save()}
    198194
    199195                def evBL = new Event(
     
    203199                )
    204200                .setFieldValue( 'Control','false' )
    205                 .with { if (!validate()) { errors.each { println it} } else save()}
    206201
    207202                def evLF4 = new Event(
     
    211206                )
    212207                .setFieldValue( 'Diet','low fat')
    213                 .with { if (!validate()) { errors.each { println it} } else save()}
    214208
    215209                def evHF4 = new Event(
     
    219213                )
    220214                .setFieldValue( 'Diet','high fat' )
    221                 .with { if (!validate()) { errors.each { println it} } else save()}
    222215
    223216                def evBV4 = new Event(
     
    227220                )
    228221                .setFieldValue( 'Control','true' )
    229                 .with { if (!validate()) { errors.each { println it} } else save()}
    230222
    231223                def evBL4 = new Event(
     
    235227                )
    236228                .setFieldValue( 'Control','false' )
    237                 .with { if (!validate()) { errors.each { println it} } else save()}
    238229
    239230                def evS = new SamplingEvent(
     
    242233                        template: liverSamplingEventTemplate)
    243234                .setFieldValue('Sample weight',5F)
    244                 .with { if (!validate()) { errors.each { println it} } else save()}
    245235
    246236                def evS4 = new SamplingEvent(
     
    249239                        template: liverSamplingEventTemplate)
    250240                .setFieldValue('Sample weight',5F)
    251                 .with { if (!validate()) { errors.each { println it} } else save()}
    252241
    253242                // Add events to study
     
    263252                .addToSamplingEvents(evS)
    264253                .addToSamplingEvents(evS4)
    265                 .save()
     254                .with { if (!validate()) { errors.each { println it} } else save()}
     255
     256                // Extra check if the SamplingEvents are saved correctly
     257                evS.with { if (!validate()) { errors.each { println it} } else save()}
     258                evS4.with { if (!validate()) { errors.each { println it} } else save()}
    266259
    267260                def LFBV1 = new EventGroup(name:"10% fat + vehicle for 1 week")
    268261                .addToEvents(evLF)
    269262                .addToEvents(evBV)
    270                 .addToEvents(evS)
    271                 .with { if (!validate()) { errors.each { println it} } else save()}
     263                .addToSamplingEvents(evS)
    272264
    273265                def LFBL1 = new EventGroup(name:"10% fat + leptin for 1 week")
    274266                .addToEvents(evLF)
    275267                .addToEvents(evBL)
    276                 .addToEvents(evS)
    277                 .with { if (!validate()) { errors.each { println it} } else save()}
     268                .addToSamplingEvents(evS)
    278269
    279270                def HFBV1 = new EventGroup(name:"45% fat + vehicle for 1 week")
    280271                .addToEvents(evHF)
    281272                .addToEvents(evBV)
    282                 .addToEvents(evS)
    283                 .with { if (!validate()) { errors.each { println it} } else save()}
     273                .addToSamplingEvents(evS)
    284274
    285275                def HFBL1 = new EventGroup(name:"45% fat + leptin for 1 week")
    286276                .addToEvents(evHF)
    287277                .addToEvents(evBL)
    288                 .addToEvents(evS)
    289                 .with { if (!validate()) { errors.each { println it} } else save()}
     278                .addToSamplingEvents(evS)
    290279
    291280                def LFBV4 = new EventGroup(name:"10% fat + vehicle for 4 weeks")
    292281                .addToEvents(evLF4)
    293282                .addToEvents(evBV4)
    294                 .addToEvents(evS4)
    295                 .with { if (!validate()) { errors.each { println it} } else save()}
     283                .addToSamplingEvents(evS4)
    296284
    297285                def LFBL4 = new EventGroup(name:"10% fat + leptin for 4 weeks")
    298286                .addToEvents(evLF4)
    299287                .addToEvents(evBL4)
    300                 .addToEvents(evS4)
    301                 .with { if (!validate()) { errors.each { println it} } else save()}
     288                .addToSamplingEvents(evS4)
    302289
    303290                def HFBV4 = new EventGroup(name:"45% fat + vehicle for 4 weeks")
    304291                .addToEvents(evHF4)
    305292                .addToEvents(evBV4)
    306                 .addToEvents(evS4)
    307                 .with { if (!validate()) { errors.each { println it} } else save()}
     293                .addToSamplingEvents(evS4)
    308294
    309295                def HFBL4 = new EventGroup(name:"45% fat + leptin for 4 weeks")
    310296                .addToEvents(evHF4)
    311297                .addToEvents(evBL4)
    312                 .addToEvents(evS4)
    313                 .with { if (!validate()) { errors.each { println it} } else save()}
    314 
     298                .addToSamplingEvents(evS4)
     299               
    315300        // Add subjects and samples and compose EventGroups
    316301                def x=1
    317                 20.times {
     302                80.times {
    318303                        def currentSubject = new Subject(
    319304                                name: "A" + x++,
     
    325310                        .setFieldValue("Age", 17)
    326311                        .setFieldValue("Cage", "" + (int)(x/2))
    327                         .with { if (!validate()) { errors.each { println it} } else save(flush:true)}
    328312
    329313                        mouseStudy.addToSubjects(currentSubject)
     
    344328                                name: currentSubject.name + '_B',
    345329                                material: bloodTerm,
    346                                         template: humanBloodSampleTemplate,
     330                                template: humanBloodSampleTemplate,
    347331                                parentSubject: currentSubject,
    348332                                parentEvent: x > 40 ? evS4 : evS
    349333                        );
    350                         currentSample.setFieldValue( "Text on vial", "T" + (Math.random() * 100L) )
    351 
     334                        currentSample.setFieldValue( "Text on vial", "T" + (Math.random() * 100L) )
    352335                        mouseStudy.addToSamples(currentSample).with { if (!validate()) { errors.each { println it} } else save()}
    353336                }
     
    363346                .addToEventGroups(HFBV4)
    364347                .addToEventGroups(HFBL4)
     348                .with { if (!validate()) { errors.each { println it} } else save()}
    365349
    366350                // Add persons and publications to study
    367                 def studyperson1 = new StudyPerson( person: person1, role: role1 ).save();
    368                 def studyperson2 = new StudyPerson( person: person2, role: role2 ).save();
     351                def studyperson1 = new StudyPerson( person: person1, role: role1 )
     352                def studyperson2 = new StudyPerson( person: person2, role: role2 )
    369353
    370354                mouseStudy
     
    373357        .addToPublications( publication1 )
    374358        .addToPublications( publication2 )
    375                 .save()
     359                .with { if (!validate()) { errors.each { println it} } else save()}
    376360
    377361                // Add example human study
     
    406390
    407391                rootGroup.addToEvents fastingEvent
    408                 rootGroup.addToEvents bloodSamplingEvent
     392                rootGroup.addToSamplingEvents bloodSamplingEvent
    409393                rootGroup.save()
    410394
     
    422406                        .setFieldValue("Weight", Math.random() * 150F)
    423407                        .setFieldValue("BMI", 20 + Math.random() * 10F)
    424                         .with { if (!validate()) { errors.each { println it} } else save()}
    425408
    426409                        rootGroup.addToSubjects currentSubject
    427                          rootGroup.save()
     410                        rootGroup.save()
    428411
    429412                        def currentSample = new Sample(
    430413                                name: currentSubject.name + '_B',
    431414                                material: bloodTerm,
    432                                         template: humanBloodSampleTemplate,
     415                                template: humanBloodSampleTemplate,
    433416                                parentSubject: currentSubject,
    434417                                parentEvent: bloodSamplingEvent
    435418                        );
    436                                 currentSample.setFieldValue( "Text on vial", "T" + (Math.random() * 100L) )
    437 
    438                         humanStudy.addToSubjects(currentSubject).addToSamples(currentSample).with { if (!validate()) { errors.each { println it} } else save()}
     419                        currentSample.setFieldValue( "Text on vial", "T" + (Math.random() * 100L) )
     420
     421                        humanStudy.addToSubjects(currentSubject).addToSamples(currentSample)
     422                        .with { if (!validate()) { errors.each { println it} } else save()}
    439423                }
    440424
     
    445429
    446430                // Add persons to study
    447                 def studyperson3 = new StudyPerson( person: person1, role: role2 ).save();
     431                def studyperson3 = new StudyPerson( person: person1, role: role2 )
    448432
    449433                humanStudy
    450434                .addToPersons( studyperson3 )
    451                         .addToPublications( publication2 )
    452                 .save()
     435                .addToPublications( publication2 )
     436                .with { if (!validate()) { errors.each { println it} } else save()}
    453437
    454438                // Add clinical data       ==> to be moved to SAM
     
    519503                }
    520504
    521                 mouseStudy.addToAssays(lipidAssayRef);
     505                mouseStudy.addToAssays(lipidAssayRef);
    522506                mouseStudy.save()
    523507
  • trunk/grails-app/domain/dbnp/studycapturing/Assay.groovy

    r690 r754  
    66 * this data can be found.
    77 */
    8 class Assay {
     8class Assay implements Serializable {
     9
     10        /** The name of the assay, which should indicate the measurements represented in this assay to the user. */
    911        String name
     12
     13        /** The dbNP module in which the assay omics data can be found. */
    1014        AssayModule module
    11         long externalAssayID // the assay ID the assay has in the external module
    1215
     16        /**
     17                The assay ID which is used in the dbNP submodule which contains the actual omics data of this assay.
     18                This ID is generated in GSCF, but is used in the submodules to refer to this particular Assay.
     19         */
     20        long externalAssayID
     21
     22        // An Assay always belongs to one study.
    1323        static belongsTo = [parent: Study]
    1424
     25        // An Assay can have many samples on which it is performed, but all samples should be within the 'parent' Study.
    1526        static hasMany = [samples: Sample]
    1627
  • trunk/grails-app/domain/dbnp/studycapturing/AssayModule.groovy

    r690 r754  
    44 * This entity describes actual dbNP submodule instances: what type of data they store, and how to reach them 
    55 */
    6 class AssayModule {
     6class AssayModule implements Serializable {
     7       
     8        /** The name of the module, for user-reference purposes  */
    79        String name
     10
     11        /** The type of the module */
    812        AssayType type
     13
     14        /** A descriptive string describing the 'platform' of the assay data in the module */
    915        String platform
     16
     17        /** The base URL at which the module instance is located */
    1018        String url
    1119
  • trunk/grails-app/domain/dbnp/studycapturing/AssayType.groovy

    r654 r754  
    22
    33/**
    4  * Enum describing the different assay types (aka omics submodules).
     4 * Enum describing the different assay types (aka known dbNP submodules).
    55 *
    66 * Revision information:
     
    99 * $Date$
    1010 */
    11 public enum AssayType {
     11public enum AssayType implements Serializable {
    1212        TRANSCRIPTOMICS('Transcriptomics'),
    1313        METABOLOMICS('Metabolomics'),
  • trunk/grails-app/domain/dbnp/studycapturing/Event.groovy

    r701 r754  
    11package dbnp.studycapturing
    2 
    3 import groovy.time.*
    42
    53/**
     
    1311 * $Date$
    1412 */
    15 class Event extends TemplateEntity implements Serializable {
    16         long startTime  // start time of the event, relative to the start time of the study
    17         long endTime    // end time of the event, relative to the start time of the study
     13class Event extends TemplateEntity {
    1814
    19         // TODO: assure the Event has a parent study in validate()
     15        static belongsTo = [parent : Study]     
     16
     17        /** Start time of the event, relative to the start time of the study */
     18        long startTime
     19        /** end time of the event, relative to the start time of the study */
     20        long endTime
    2021
    2122        /**
     
    4142        }
    4243
     44        static mapping = {
     45
     46                // Specify that subclasses for Event should have their own database table.
     47                // This is done because otherwise we run into troubles with the SamplingEvent references from Study.
     48                tablePerHierarchy false
     49        }
     50
    4351        /**
    4452         * return the domain fields for this domain class
    45          * @return List
     53         * @return List<TemplateField>
    4654         */
    4755        static List<TemplateField> giveDomainFields() { return Event.domainFields }
    4856
     57        // To improve performance, the domain fields list is stored as a static final variable in the class.
    4958        static final List<TemplateField> domainFields = [
    5059                new TemplateField(
     
    5968
    6069        /**
    61          * get the duration
     70         * Get the duration of the event as RelTime
    6271         * @return RelTime
    6372         */
     
    6574                return new RelTime(startTime, endTime)
    6675        }
    67 
    6876
    6977         /**
     
    8593
    8694        /**
    87          * get a prettified duration
    88          * @return String
    89          */
    90         static def getPrettyDuration(RelTime duration) {
    91                 return duration.toPrettyString();
    92         }
    93 
    94         def getPrettyDuration() {
    95                 getPrettyDuration(getDuration())
    96         }
    97 
    98         /**
    9995         * Get human readable string representing the duration between startTime and endTime, rounded to one unit (weeks/days/hours etc.)
    10096     *
     
    113109        }
    114110
     111        /**
     112         * Checks whether this Event is part of one or more of the given EventGroups
     113         * @param groups
     114         * @return
     115         */
    115116        def belongsToGroup(Collection<EventGroup> groups) {
    116117                def eventFound = false;
  • trunk/grails-app/domain/dbnp/studycapturing/EventGroup.groovy

    r496 r754  
    1010 */
    1111class EventGroup implements Serializable {
     12
     13        static belongsTo = [parent : Study]
     14
    1215        String name
    1316
    1417        static hasMany = [
    1518                subjects: Subject,
    16                 events: Event
     19                events: Event,
     20                samplingEvents: SamplingEvent
    1721        ]
    1822
  • trunk/grails-app/domain/dbnp/studycapturing/Person.groovy

    r540 r754  
    22
    33/**
    4  * 888       888 888    888 8888888888 8888888b.  8888888888
    5  * 888   o   888 888    888 888        888   Y88b 888
    6  * 888  d8b  888 888    888 888        888    888 888
    7  * 888 d888b 888 8888888888 8888888    888   d88P 8888888
    8  * 888d88888b888 888    888 888        8888888P"  888
    9  * 88888P Y88888 888    888 888        888 T88b   888
    10  * 8888P   Y8888 888    888 888        888  T88b  888
    11  * 888P     Y888 888    888 8888888888 888   T88b 8888888888
    12  *
    13  * 8888888 .d8888b.     88888888888 888    888 8888888888
    14  *   888  d88P  Y88b        888     888    888 888
    15  *   888  Y88b.             888     888    888 888
    16  *   888   "Y888b.          888     8888888888 8888888
    17  *   888      "Y88b.        888     888    888 888
    18  *   888        "888        888     888    888 888
    19  *   888  Y88b  d88P        888     888    888 888
    20  * 8888888 "Y8888P"         888     888    888 8888888888
    21  *
    22  *   888888        d8888 888     888     d8888 8888888b.   .d88888b.   .d8888b.
    23  *     "88b       d88888 888     888    d88888 888  "Y88b d88P" "Y88b d88P  Y88b
    24  *      888      d88P888 888     888   d88P888 888    888 888     888 888    888
    25  *      888     d88P 888 Y88b   d88P  d88P 888 888    888 888     888 888
    26  *      888    d88P  888  Y88b d88P  d88P  888 888    888 888     888 888
    27  *      888   d88P   888   Y88o88P  d88P   888 888    888 888     888 888    888
    28  *      88P  d8888888888    Y888P  d8888888888 888  .d88P Y88b. .d88P Y88b  d88P
    29  *      888 d88P     888     Y8P  d88P     888 8888888P"   "Y88888P"   "Y8888P"
    30  *    .d88P
    31  *  .d88P"
    32  * 888P"
    33  *
    34  *  .d8888b.  888  .d8888b.  888  .d8888b.  888
    35  * d88P  Y88b 888 d88P  Y88b 888 d88P  Y88b 888
    36  *      .d88P 888      .d88P 888      .d88P 888
    37  *    .d88P"  888    .d88P"  888    .d88P"  888
    38  *    888"    888    888"    888    888"    888
    39  *    888     Y8P    888     Y8P    888     Y8P
    40  *             "              "              "
    41  *    888     888    888     888    888     888
    42  *
    43  *
    44  * TODO: add PROPER class and method documentation, just like have
    45  *       agreed upon hundreds of times!!!!
     4 * The Person class represents a person who is related to one ore more studies, such as a PI, a lab analyst etc.
     5 * Those people do not neccessarily have an account in GSCF, the Study/Persons/Affiliations administration
     6 * is independent of GSCF usernames and accounts.
    467 */
    47 
    488class Person implements Serializable {
    499        String title
  • trunk/grails-app/domain/dbnp/studycapturing/PersonAffiliation.groovy

    r540 r754  
    22
    33/**
    4  * 888       888 888    888 8888888888 8888888b.  8888888888
    5  * 888   o   888 888    888 888        888   Y88b 888
    6  * 888  d8b  888 888    888 888        888    888 888
    7  * 888 d888b 888 8888888888 8888888    888   d88P 8888888
    8  * 888d88888b888 888    888 888        8888888P"  888
    9  * 88888P Y88888 888    888 888        888 T88b   888
    10  * 8888P   Y8888 888    888 888        888  T88b  888
    11  * 888P     Y888 888    888 8888888888 888   T88b 8888888888
    12  *
    13  * 8888888 .d8888b.     88888888888 888    888 8888888888
    14  *   888  d88P  Y88b        888     888    888 888
    15  *   888  Y88b.             888     888    888 888
    16  *   888   "Y888b.          888     8888888888 8888888
    17  *   888      "Y88b.        888     888    888 888
    18  *   888        "888        888     888    888 888
    19  *   888  Y88b  d88P        888     888    888 888
    20  * 8888888 "Y8888P"         888     888    888 8888888888
    21  *
    22  *   888888        d8888 888     888     d8888 8888888b.   .d88888b.   .d8888b.
    23  *     "88b       d88888 888     888    d88888 888  "Y88b d88P" "Y88b d88P  Y88b
    24  *      888      d88P888 888     888   d88P888 888    888 888     888 888    888
    25  *      888     d88P 888 Y88b   d88P  d88P 888 888    888 888     888 888
    26  *      888    d88P  888  Y88b d88P  d88P  888 888    888 888     888 888
    27  *      888   d88P   888   Y88o88P  d88P   888 888    888 888     888 888    888
    28  *      88P  d8888888888    Y888P  d8888888888 888  .d88P Y88b. .d88P Y88b  d88P
    29  *      888 d88P     888     Y8P  d88P     888 8888888P"   "Y88888P"   "Y8888P"
    30  *    .d88P
    31  *  .d88P"
    32  * 888P"
    33  *
    34  *  .d8888b.  888  .d8888b.  888  .d8888b.  888
    35  * d88P  Y88b 888 d88P  Y88b 888 d88P  Y88b 888
    36  *      .d88P 888      .d88P 888      .d88P 888
    37  *    .d88P"  888    .d88P"  888    .d88P"  888
    38  *    888"    888    888"    888    888"    888
    39  *    888     Y8P    888     Y8P    888     Y8P
    40  *             "              "              "
    41  *    888     888    888     888    888     888
    42  *
    43  *
    44  * TODO: add PROPER class and method documentation, just like have
    45  *       agreed upon hundreds of times!!!!
     4 * The PersonAffiliation class is an attribute of a Person, it represents an affiliation where she/he works for.
     5 * PersonAffiliation is an independent list of affiliations, and does not neccessarily belong to one Person.
    466 */
     7class PersonAffiliation implements Serializable {
    478
    48 class PersonAffiliation implements Serializable {
    499        String institute
    5010        String department
  • trunk/grails-app/domain/dbnp/studycapturing/PersonRole.groovy

    r540 r754  
    22
    33/**
    4  * 888       888 888    888 8888888888 8888888b.  8888888888
    5  * 888   o   888 888    888 888        888   Y88b 888
    6  * 888  d8b  888 888    888 888        888    888 888
    7  * 888 d888b 888 8888888888 8888888    888   d88P 8888888
    8  * 888d88888b888 888    888 888        8888888P"  888
    9  * 88888P Y88888 888    888 888        888 T88b   888
    10  * 8888P   Y8888 888    888 888        888  T88b  888
    11  * 888P     Y888 888    888 8888888888 888   T88b 8888888888
    12  *
    13  * 8888888 .d8888b.     88888888888 888    888 8888888888
    14  *   888  d88P  Y88b        888     888    888 888
    15  *   888  Y88b.             888     888    888 888
    16  *   888   "Y888b.          888     8888888888 8888888
    17  *   888      "Y88b.        888     888    888 888
    18  *   888        "888        888     888    888 888
    19  *   888  Y88b  d88P        888     888    888 888
    20  * 8888888 "Y8888P"         888     888    888 8888888888
    21  *
    22  *   888888        d8888 888     888     d8888 8888888b.   .d88888b.   .d8888b.
    23  *     "88b       d88888 888     888    d88888 888  "Y88b d88P" "Y88b d88P  Y88b
    24  *      888      d88P888 888     888   d88P888 888    888 888     888 888    888
    25  *      888     d88P 888 Y88b   d88P  d88P 888 888    888 888     888 888
    26  *      888    d88P  888  Y88b d88P  d88P  888 888    888 888     888 888
    27  *      888   d88P   888   Y88o88P  d88P   888 888    888 888     888 888    888
    28  *      88P  d8888888888    Y888P  d8888888888 888  .d88P Y88b. .d88P Y88b  d88P
    29  *      888 d88P     888     Y8P  d88P     888 8888888P"   "Y88888P"   "Y8888P"
    30  *    .d88P
    31  *  .d88P"
    32  * 888P"
    33  *
    34  *  .d8888b.  888  .d8888b.  888  .d8888b.  888
    35  * d88P  Y88b 888 d88P  Y88b 888 d88P  Y88b 888
    36  *      .d88P 888      .d88P 888      .d88P 888
    37  *    .d88P"  888    .d88P"  888    .d88P"  888
    38  *    888"    888    888"    888    888"    888
    39  *    888     Y8P    888     Y8P    888     Y8P
    40  *             "              "              "
    41  *    888     888    888     888    888     888
    42  *
    43  *
    44  * TODO: add PROPER class and method documentation, just like have
    45  *       agreed upon hundreds of times!!!!
     4 * The role of a person, as specified in a StudyPerson relation.
     5 * Person roles form an independent 'roles list' and are therefore not coupled to a specific StudyPerson relation with belongsTo.
     6 * Generally, there will only be a few PersonRoles such as PI, lab analyst etc.
    467 */
     8class PersonRole implements Serializable {
    479
    48 class PersonRole implements Serializable {
     10        /** The name of the role, such as Project Leader or PI */
    4911        String name
    5012
  • trunk/grails-app/domain/dbnp/studycapturing/Publication.groovy

    r540 r754  
    22
    33/**
    4  * 888       888 888    888 8888888888 8888888b.  8888888888
    5  * 888   o   888 888    888 888        888   Y88b 888
    6  * 888  d8b  888 888    888 888        888    888 888
    7  * 888 d888b 888 8888888888 8888888    888   d88P 8888888
    8  * 888d88888b888 888    888 888        8888888P"  888
    9  * 88888P Y88888 888    888 888        888 T88b   888
    10  * 8888P   Y8888 888    888 888        888  T88b  888
    11  * 888P     Y888 888    888 8888888888 888   T88b 8888888888
    12  *
    13  * 8888888 .d8888b.     88888888888 888    888 8888888888
    14  *   888  d88P  Y88b        888     888    888 888
    15  *   888  Y88b.             888     888    888 888
    16  *   888   "Y888b.          888     8888888888 8888888
    17  *   888      "Y88b.        888     888    888 888
    18  *   888        "888        888     888    888 888
    19  *   888  Y88b  d88P        888     888    888 888
    20  * 8888888 "Y8888P"         888     888    888 8888888888
    21  *
    22  *   888888        d8888 888     888     d8888 8888888b.   .d88888b.   .d8888b.
    23  *     "88b       d88888 888     888    d88888 888  "Y88b d88P" "Y88b d88P  Y88b
    24  *      888      d88P888 888     888   d88P888 888    888 888     888 888    888
    25  *      888     d88P 888 Y88b   d88P  d88P 888 888    888 888     888 888
    26  *      888    d88P  888  Y88b d88P  d88P  888 888    888 888     888 888
    27  *      888   d88P   888   Y88o88P  d88P   888 888    888 888     888 888    888
    28  *      88P  d8888888888    Y888P  d8888888888 888  .d88P Y88b. .d88P Y88b  d88P
    29  *      888 d88P     888     Y8P  d88P     888 8888888P"   "Y88888P"   "Y8888P"
    30  *    .d88P
    31  *  .d88P"
    32  * 888P"
    33  *
    34  *  .d8888b.  888  .d8888b.  888  .d8888b.  888
    35  * d88P  Y88b 888 d88P  Y88b 888 d88P  Y88b 888
    36  *      .d88P 888      .d88P 888      .d88P 888
    37  *    .d88P"  888    .d88P"  888    .d88P"  888
    38  *    888"    888    888"    888    888"    888
    39  *    888     Y8P    888     Y8P    888     Y8P
    40  *             "              "              "
    41  *    888     888    888     888    888     888
    42  *
    43  *
    44  * TODO: add PROPER class and method documentation, just like have
    45  *       agreed upon hundreds of times!!!!
     4 * The Publication class represents a PubMed-registered publication.
     5 * Publication entries should be created using the study wizard, which connects to PubMed to fill in the fields.
     6 * Since a Publication can apply to multiple studies, the entries in this table form an independent 'library'
     7 * and are not connected to Study instances via a cascading relation.
    468 */
    47 
    489class Publication implements Serializable {
    4910        String title
    5011        String pubMedID
    51         String DOI
     12        String DOI      // document identifier, see dx.doi.org
    5213        String authorsList
    5314        String comments
  • trunk/grails-app/domain/dbnp/studycapturing/RelTime.groovy

    r580 r754  
    22 * RelTime Domain Class
    33 *
    4  * Contains useful functions for the RelTime templatefield
     4 * A RelTime is a TemplateFieldType that specifies a relative time aka timespan.
     5 * The timespan is saved as a long value representing the number of seconds in the timespan.
     6 * A human-readable representation of this number is generated, which renders e.g. '4d 2h' for 4 days 2 hours.
     7 * Also, a parser is implemented which can interpret such entries when they are entered by the user.
     8 *
     9 * This class is purely a helper class to manipulate long fields that represent relative times.
     10 * There will be no data in the database in the table that is created for this class (probably named rel_time).
    511 *
    612 * @author Robert Horlings
  • trunk/grails-app/domain/dbnp/studycapturing/Sample.groovy

    r697 r754  
    1111        //static searchable = { [only: ['name']] }
    1212
    13         static belongsTo = [ parent : Study]
     13        // A Sample always belongs to one study.
     14        static belongsTo = [parent : Study]
    1415
     16        // A Sample optionally has a parent Subject from which it was taken, this Subject should be in the same parent study.
    1517        Subject parentSubject
     18
     19        // Also, it has a parent SamplingEvent describing the actual sampling, also within the same parent study.
    1620        SamplingEvent parentEvent
    1721
     
    2630         */
    2731        static List<TemplateField> giveDomainFields() { return Sample.domainFields }
     32
     33        // We have to specify an ontology list for the material property. However, at compile time, this ontology does of course not exist.
     34        // Therefore, the ontology is added at runtime in the bootstrap, possibly downloading the ontology properties if it is not present in the database yet.
    2835        static List<TemplateField> domainFields = [
    2936                new TemplateField(
     
    4047
    4148        static constraints = {
     49                // The parent subject is optional, e.g. in a biobank of samples the subject could be unknown or non-existing.
    4250                parentSubject(nullable:true)
     51
     52                // The material domain field is optional
    4353                material(nullable: true)
    4454
    45                 // Checks if the externalSampleId (currently defined as name) is really unique within each parent study of this sample.
     55                // Check if the externalSampleId (currently defined as name) is really unique within each parent study of this sample.
    4656                // This feature is tested by integration test SampleTests.testSampleUniqueNameConstraint
    4757                name(unique:['parent'])
  • trunk/grails-app/domain/dbnp/studycapturing/SamplingEvent.groovy

    r654 r754  
    44 * The SamplingEvent class describes a sampling event, an event that also results in one or more samples.
    55 *
    6  * NOTE: according to documentation, super classes and subclasses share the same table.
     6 * NOTE: according to Grails documentation, super classes and subclasses share the same table.
    77 *       thus, we could merge the sampling with the Event super class and include a boolean
    88 *       However, using a separate class makes it more clear in the code that Event and SamplingEvent are treated differently
    99 */
     10class SamplingEvent extends TemplateEntity {
    1011
    11 class SamplingEvent extends Event {
     12        // A SamplingEvent always belongs to one study.
     13        // Although this is technically inherited from Event, we have to specify it here again.
     14        // Otherwise, Grails expects the SamplingEvent to be referenced in Study.events,
     15        // where it is actually referenced in Study.samplingEvents
     16        static belongsTo = [parent : Study]
     17
     18        static hasMany = [samples : Sample]
     19
     20        /** Start time of the event, relative to the start time of the study */
     21        long startTime
     22
     23        /** Duration of the sampling event, if it has any (default is 0) */
     24        long duration
    1225
    1326        static constraints = {
     27                duration(default: 0L)
    1428        }
     29
     30        /**
     31         * return the domain fields for this domain class
     32         * @return List<TemplateField>
     33         */
     34        static List<TemplateField> giveDomainFields() { return SamplingEvent.domainFields }
     35
     36        // To improve performance, the domain fields list is stored as a static final variable in the class.
     37        static final List<TemplateField> domainFields = [
     38                new TemplateField(
     39                        name: 'startTime',
     40                        type: TemplateFieldType.RELTIME,
     41                        comment: "Please enter the start time as a relative time from study start date."+RelTime.getHelpText()),
     42                new TemplateField(
     43                        name: 'duration',
     44                        type: TemplateFieldType.RELTIME,
     45                        comment: "Please enter the duration of the sampling action, if applicable. "+RelTime.getHelpText())
     46        ]
     47
     48        /**
     49         * Get the duration of the event as RelTime
     50         * @return RelTime
     51         */
     52        /*RelTime getDuration() {
     53                return new RelTime(duration)
     54        }*/
     55
     56         /**
     57          * Return the start time of the event, which should be relative to the start of the study
     58          * @return String a human readable representation of the start time of the event
     59         */
     60        def getStartTimeString() {
     61                return new RelTime(startTime).toPrettyString();
     62        }
     63
     64        /**
     65         * Get extended, human readable string representing the duration between startTime and endTime
     66     *
     67         * @return String
     68         */
     69        def getDurationString() {
     70                return new RelTime(duration).toPrettyString();
     71        }
     72
     73        /**
     74         * Checks whether this Event is part of one or more of the given EventGroups
     75         * @param groups
     76         * @return
     77         */
     78        def belongsToGroup(Collection<EventGroup> groups) {
     79                def eventFound = false;
     80                def that = this;
     81                groups.each { eventgroup ->
     82                        if (!eventFound) {
     83                                eventFound = (that.id in eventgroup.events.id);
     84                        }
     85                }
     86
     87                return eventFound;
     88        }       
    1589
    1690        /**
  • trunk/grails-app/domain/dbnp/studycapturing/Study.groovy

    r667 r754  
    99 * $Date$
    1010 */
    11 class Study extends TemplateEntity implements Serializable {
     11class Study extends TemplateEntity {
    1212        static searchable = {
    1313        [only: ['title', 'Description']]
    1414    }
    1515
    16         nimble.User owner
    17         String title
    18         String code             // also enables referencing to studies from the Simple Assay Module
     16        nimble.User owner   // The owner of the study. A new study is automatically owned by its creator.
     17        String title        // The title of the study
     18        String code             // currently used as the external study ID, e.g. to reference a study in a SAM module
    1919        Date dateCreated
    2020        Date lastUpdated
     
    2828
    2929        static hasMany = [
    30                 editors: nimble.User,
    31                 readers: nimble.User,
     30                editors: nimble.User,   // Users with read/write access to the study
     31                readers: nimble.User,   // Users with only read access to the study
    3232                subjects: Subject,
     33                samplingEvents: SamplingEvent,
    3334                events: Event,
    34                 samplingEvents: SamplingEvent,
    3535                eventGroups: EventGroup,
    3636                samples: Sample,
     
    5050                autoTimestamp true
    5151        }
     52
     53        // The external study ID is currently defined as the code of the study.
     54        // It is used from within dbNP submodules to refer to particular study in this GSCF instance.
     55        def getExternalStudyId() { code }
    5256
    5357        /**
  • trunk/grails-app/domain/dbnp/studycapturing/StudyPerson.groovy

    r540 r754  
    11package dbnp.studycapturing
    2 
    3 /**
    4  * 888       888 888    888 8888888888 8888888b.  8888888888
    5  * 888   o   888 888    888 888        888   Y88b 888
    6  * 888  d8b  888 888    888 888        888    888 888
    7  * 888 d888b 888 8888888888 8888888    888   d88P 8888888
    8  * 888d88888b888 888    888 888        8888888P"  888
    9  * 88888P Y88888 888    888 888        888 T88b   888
    10  * 8888P   Y8888 888    888 888        888  T88b  888
    11  * 888P     Y888 888    888 8888888888 888   T88b 8888888888
    12  *
    13  * 8888888 .d8888b.     88888888888 888    888 8888888888
    14  *   888  d88P  Y88b        888     888    888 888
    15  *   888  Y88b.             888     888    888 888
    16  *   888   "Y888b.          888     8888888888 8888888
    17  *   888      "Y88b.        888     888    888 888
    18  *   888        "888        888     888    888 888
    19  *   888  Y88b  d88P        888     888    888 888
    20  * 8888888 "Y8888P"         888     888    888 8888888888
    21  *
    22  *   888888        d8888 888     888     d8888 8888888b.   .d88888b.   .d8888b.
    23  *     "88b       d88888 888     888    d88888 888  "Y88b d88P" "Y88b d88P  Y88b
    24  *      888      d88P888 888     888   d88P888 888    888 888     888 888    888
    25  *      888     d88P 888 Y88b   d88P  d88P 888 888    888 888     888 888
    26  *      888    d88P  888  Y88b d88P  d88P  888 888    888 888     888 888
    27  *      888   d88P   888   Y88o88P  d88P   888 888    888 888     888 888    888
    28  *      88P  d8888888888    Y888P  d8888888888 888  .d88P Y88b. .d88P Y88b  d88P
    29  *      888 d88P     888     Y8P  d88P     888 8888888P"   "Y88888P"   "Y8888P"
    30  *    .d88P
    31  *  .d88P"
    32  * 888P"
    33  *
    34  *  .d8888b.  888  .d8888b.  888  .d8888b.  888
    35  * d88P  Y88b 888 d88P  Y88b 888 d88P  Y88b 888
    36  *      .d88P 888      .d88P 888      .d88P 888
    37  *    .d88P"  888    .d88P"  888    .d88P"  888
    38  *    888"    888    888"    888    888"    888
    39  *    888     Y8P    888     Y8P    888     Y8P
    40  *             "              "              "
    41  *    888     888    888     888    888     888
    42  *
    43  *
    44  * TODO: add PROPER class and method documentation, just like have
    45  *       agreed upon hundreds of times!!!!
    46  */
    472
    483/**
     
    505 */
    516class StudyPerson implements Serializable {
    52     Person person
    53     PersonRole role
     7
     8        // A StudyPerson relation always belongs to one study.
     9        static belongsTo = [parent : Study]
     10
     11    /** The Person which is referenced in the Study */
     12        Person person
     13
     14        /** The role this Person has in the Study */
     15        PersonRole role
    5416
    5517    static constraints = {
  • trunk/grails-app/domain/dbnp/studycapturing/Subject.groovy

    r667 r754  
    1212 * $Date$
    1313 */
    14 class Subject extends TemplateEntity implements Serializable {
     14class Subject extends TemplateEntity {
    1515        // uncommented due to searchable issue
    1616        // @see http://jira.codehaus.org/browse/GRAILSPLUGINS-1577
    1717        //static searchable = { [only: ['name']] }
    1818
     19        // A Subject always belongs to one Study
     20        static belongsTo = [parent : Study]
     21
     22        /** The name of the subject, which should be unique within the study */
    1923        String name
     24
     25        /** The species of the subject. In the domainFields property, the ontologies from which this term may come are specified. */
    2026        Term species
     27
     28        static constraints = {
     29                // Ensure that the subject name is unique within the study
     30                name(unique:['parent'])
     31        }
     32
    2133
    2234        /**
     
    2638        static List<TemplateField> giveDomainFields() { return Subject.domainFields; }
    2739
     40        // We have to specify an ontology list for the species property. However, at compile time, this ontology does of course not exist.
     41        // Therefore, the ontology is added at runtime in the bootstrap, possibly downloading the ontology properties if it is not present in the database yet.
    2842        static List<TemplateField> domainFields = [
    2943                new TemplateField(
  • trunk/grails-app/domain/dbnp/studycapturing/Template.groovy

    r556 r754  
    11package dbnp.studycapturing
    2 import java.lang.reflect.Method
    32
    43/**
    5  * The Template class describes a study template, which is basically an extension of the study capture entities
    6  * in terms of extra fields (described by classes that extend the TemplateField class).
    7  * At this moment, only extension of the study and subject entities is implemented.
     4 * The Template class describes a TemplateEntity template, which is basically an extension of the study capture entities
     5 * in terms of extra fields (which are described by classes that extend the TemplateField class).
     6 * Study, Subject, Sample and Event are all TemplateEntities.
     7 *
     8 * Within a Template, we have two different types of fields: 'domain fields' and 'template fields'.
     9 * The domain fields are TemplateFields which are given by the TemplateEntity itself and therefore always present
     10 * in any instance of that TemplateEntity. They are specified by implementing TemplateEntity.giveDomainFields()
     11 * The template fields are TemplateFields which are added specifically by the Template. They are specified
     12 * in the fields property of the Template object which is referenced by the TemplateEntity.template property.
    813 *
    914 * Revision information:
     
    1318 */
    1419class Template implements Serializable {
     20
     21        /** The name of the template */
    1522        String name
     23
     24        /** A string describing the template to other users */
    1625        String description
     26
     27        /** The target TemplateEntity for this template */
    1728        Class entity
    18         //nimble.User owner
     29
     30        /** The owner of the template. If the owner is not defined, it is a shared/public template */
     31        nimble.User owner
     32
     33        /** The template fields which are the members of this template. This is a List to preserve the field order */
    1934        List fields
    2035        static hasMany = [fields: TemplateField]
    2136
    2237        static constraints = {
     38
     39                owner(nullable: true, blank: true)
    2340                description(nullable: true, blank: true)
    2441
     
    4966                // outcommented for now due to bug in Grails / Hibernate
    5067                // see http://jira.codehaus.org/browse/GRAILS-6020
     68                // This is to verify that the template name is unique with respect to the parent entity.
     69                // TODO: this probably has to change in the case of private templates of different users,
     70                // which can co-exist with the same name. See also TemplateField
    5171                //      name(unique:['entity'])
    5272        }
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateEntity.groovy

    r725 r754  
    55
    66/**
    7  * TemplateEntity Domain Class
     7 * The TemplateEntity domain Class is a superclass for all template-enabled study capture entities, including
     8 * Study, Subject, Sample and Event. This class provides functionality for storing the different TemplateField
     9 * values and returning the combined list of 'domain fields' and 'template fields' of a TemplateEntity.
     10 * For an explanation of those terms, see the Template class.
     11 *
     12 * @see dbnp.studycapturing.Template
    813 *
    914 * Revision information:
     
    1318 */
    1419abstract class TemplateEntity implements Serializable {
     20
     21        /** The actual template of this TemplateEntity instance */
    1522        Template template
     23
     24        // Maps for storing the different template field values
    1625        Map templateStringFields = [:]
    1726        Map templateTextFields = [:]
     
    4554
    4655        static mapping = {
     56
     57                // Specify that each TemplateEntity-subclassing entity should have its own tables to store TemplateField values.
     58                // This results in a lot of tables, but performance is presumably better because in most queries, only values of
     59                // one specific entity will be retrieved. Also, because of the generic nature of these tables, they can end up
     60                // containing a lot of records (there is a record for each entity instance for each property, instead of a record
     61                // for each instance as is the case with 'normal' straightforward database tables. Therefore, it's better to split
     62                // out the data to many tables.
    4763                tablePerHierarchy false
    4864
     65                // Make sure that the text fields are really stored as TEXT, so that those Strings can have an arbitrary length.
    4966                templateTextFields type: 'text'
    5067        }
    5168
     69        // Inject the service for storing files (for TemplateFields of TemplateFieldType FILE).
    5270        def fileService
    5371
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateField.groovy

    r556 r754  
    44
    55/**
    6  * This is the class for template fields. These should be part of one or more templates via Template.fields
     6 * A TemplateField is a specification for either a 'domain field' of a subclass of TemplateEntity or a
     7 * 'template field' for a specific Template. See the Template class for an explanation of these terms.
     8 * The TemplateField class contains all information which is needed to specify what kind of data can be stored
     9 * in this particular field, such as the TemplateFieldType, the name, the ontologies from which terms can derive
     10 * in case of an ONTOLOGYTERM field, the list entries in case of a STRINGLIST fields, and so on.
     11 * The actual values of the template fields are stored in instances of subclasses of the TemplateEntity class.
     12 * For example, if there exists a Study template with a 'description' TemplateField as a member of Template.fields,
     13 * the actual description for each Study would be stored in the inherited templateStringFields map of that Study instance.
     14 *
     15 * One TemplateField can belong to many Templates, but they have to be the same entity as the TemplateField itself.
    716 *
    817 * Revision information:
     
    1221 */
    1322class TemplateField implements Serializable {
     23
     24        /** The name of the TemplateField, by which it is represented to the user.  */
    1425        String name
     26
     27        /** The type of this TemplateField, such as STRING, ONTOLOGYTERM etc. */
    1528        TemplateFieldType type
    16     Class entity
     29
     30        /** The entity for which this TemplateField is meant. Only Templates for this entity can contain this TemplateField */
     31        Class entity
     32
     33        /** The unit of the values of this TemplateField (optional) */
    1734        String unit
    18         String comment // help string for the user interface
     35
     36        /** The help string which is shown in the user interface to describe this template field (optional, TEXT) */
     37        String comment
     38
     39        /** The different list entries for a STRINGLIST TemplateField. This property is only used if type == TemplateFieldType.STRINGLIST */
    1940        List listEntries
     41
     42        /** Indicates whether this field is required to be filled out or not */
    2043        boolean required
     44
     45        /** Indicates whether this field is the preferred identifier for the resulting templated entity.
     46                This is for example used when importing to match entries in the database against the ones that are being imported. */
    2147        boolean preferredIdentifier
    2248
    2349        static hasMany = [
    2450                listEntries: TemplateFieldListItem,     // to store the entries to choose from when the type is 'item from predefined list'
    25                 ontologies: Ontology                                    // to store the ontologies to choose from when the type is 'ontology term'
     51                ontologies: Ontology                            // to store the ontologies to choose from when the type is 'ontology term'
    2652        ]
    2753
    2854        static constraints = {
    29                 // TODO: verify that TemplateField names are unique within templates of each super entity
     55
     56                // outcommented for now due to bug in Grails / Hibernate
     57                // see http://jira.codehaus.org/browse/GRAILS-6020
     58                // This is to verify that TemplateField names are unique within templates of each super entity
     59                // TODO: this probably has to change in the case of private templates of different users,
     60                // which can co-exist with the same name. See also Template
     61                // name(unique:['entity'])
     62
    3063                name(nullable: false, blank: false)
    3164                type(nullable: false, blank: false)
     
    3871
    3972        static mapping = {
    40                 // TODO: this doesn't seem to work in Postgres
     73                // Make sure the comments can be Strings of arbitrary length
    4174                comment type: 'text'
    4275        }
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateFieldListItem.groovy

    r496 r754  
    22
    33/**
    4  * TemplateFieldListItem Domain Class
     4 * TemplateFieldListItem Domain Class. Used to represent the list items in a STRINGLIST TemplateField.
    55 *
    66 * Revision information:
     
    1010 */
    1111class TemplateFieldListItem implements Serializable {
     12
     13        // A TemplateFieldListItem always belongs to one TemplateField of TemplateFieldType STRINGLIST
     14        static belongsTo = [parent : TemplateField]
     15
     16        /** The caption of the list item */
    1217        String name
    1318
  • trunk/grails-app/domain/dbnp/studycapturing/TemplateFieldType.groovy

    r559 r754  
    22
    33/**
    4  * Enum describing the type of a templated field.
     4 * Enum describing the type of a TemplateField.
    55 * Revision information:
    66 * $Rev$
     
    2121        BOOLEAN('Boolean')
    2222    // TODO: add a timezone-aware date type to use for study start date
    23     // TODO: add a BOOLEAN type (checkbox)
    2423
    2524    String name
  • trunk/grails-app/views/query/selectsample.gsp

    r497 r754  
    6868                 <td> ${sample.material}</td>
    6969
    70                  <td> ${event.getPrettyDuration(event.startTime)} </td>
     70                 <td> ${event.getStartTimeString()} </td>
    7171
    7272                 <td>
  • trunk/grails-app/views/study/show.gsp

    r629 r754  
    450450                    events = studyInstance.events + studyInstance.samplingEvents;
    451451                    sortedEvents = events.sort( { a, b ->
    452                           a.startTime == b.startTime ?
    453                             a.getDuration().getValue() <=> b.getDuration().getValue() :
    454                             a.startTime <=> b.startTime
     452                          //a.startTime == b.startTime ?
     453                            //a.getDuration().getValue() <=> b.getDuration().getValue() :
     454                          a.startTime <=> b.startTime
    455455                      } as Comparator )
    456456                  %>
     
    463463                        </td>
    464464                      </g:if>
    465                       <td>${new RelTime(event.startTime).toPrettyString()}</td>
    466                       <td>${event.getPrettyDuration()}</td>
     465                      <td>${event.getStartTimeString()}</td>
     466                      <td>${event.getDurationString()}</td>
    467467                      <td>${event.template.name}</td>
    468468                      <td>
Note: See TracChangeset for help on using the changeset viewer.