1 // ==========================================================================
  2 // Project:   SproutCore - JavaScript Application Framework
  3 // Copyright: ©2010 Evin Grano
  4 //            Portions ©2008-2011 Apple Inc. All rights reserved.
  5 // License:   Licensed under MIT license (see license.js)
  6 // ==========================================================================
  7 
  8 sc_require('models/record');
  9 sc_require('models/record_attribute');
 10 
 11 /** @class
 12 
 13   ChildAttribute is a subclass of `RecordAttribute` and handles to-one
 14   relationships for child records.
 15 
 16   When setting ( `.set()` ) the value of a toMany attribute, make sure
 17   to pass in an array of `SC.Record` objects.
 18 
 19   There are many ways you can configure a ManyAttribute:
 20 
 21       contacts: SC.ChildAttribute.attr('SC.Child');
 22 
 23   @extends SC.RecordAttribute
 24   @since SproutCore 1.0
 25 */
 26 SC.ChildAttribute = SC.RecordAttribute.extend(
 27   /** @scope SC.ChildAttribute.prototype */ {
 28 
 29   isNestedRecordTransform: YES,
 30 
 31   // ..........................................................
 32   // LOW-LEVEL METHODS
 33   //
 34 
 35   /**  @private - adapted for to one relationship */
 36   toType: function(record, key, value) {
 37     var ret   = null, rel,
 38         recordType  = this.get('typeClass');
 39 
 40     if (!record) {
 41       throw new Error('SC.Child: Error during transform: Unable to retrieve parent record.');
 42     }
 43     if (!SC.none(value)) ret = record.registerNestedRecord(value, key);
 44 
 45     return ret;
 46   },
 47 
 48   // Default fromType is just returning itself
 49   fromType: function(record, key, value) {
 50     var sk, store, ret;
 51 
 52     if (record) {
 53       // Unregister the old child (nested) record.
 54       if (record.readAttribute(key)) {
 55         record.unregisterNestedRecord(key);
 56       }
 57 
 58       if (SC.none(value)) {
 59         // Handle null value.
 60         record.writeAttribute(key, value);
 61         ret = value;
 62       } else {
 63         // Register the nested record with this record (the parent).
 64         ret = record.registerNestedRecord(value, key);
 65 
 66         if (ret) {
 67           // Write the data hash of the nested record to the store.
 68           sk = ret.get('storeKey');
 69           store = ret.get('store');
 70           record.writeAttribute(key, store.readDataHash(sk));
 71         } else if (value) {
 72           // If registration failed, just write the value.
 73           record.writeAttribute(key, value);
 74         }
 75       }
 76     }
 77 
 78     return ret;
 79   },
 80 
 81   /**
 82     The core handler.  Called from the property.
 83     @param {SC.Record} record the record instance
 84     @param {String} key the key used to access this attribute on the record
 85     @param {Object} value the property value if called as a setter
 86     @returns {Object} property value
 87   */
 88   call: function(record, key, value) {
 89     var attrKey = this.get('key') || key;
 90     if (value !== undefined) {
 91       value = this.fromType(record, key, value) ; // convert to attribute.
 92     } else {
 93       value = record.readAttribute(attrKey);
 94       if (SC.none(value) && (value = this.get('defaultValue'))) {
 95         if (typeof value === SC.T_FUNCTION) {
 96           value = this.defaultValue(record, key, this);
 97           // write default value so it doesn't have to be executed again
 98           if(record.attributes()) record.writeAttribute(attrKey, value, true);
 99         }
100       } else value = this.toType(record, key, value);
101     }
102 
103     return value ;
104   }
105 });
106 
107 
108