// ========================================================================== // Project: SproutCore - JavaScript Application Framework // Copyright: ©2006-2010 Sprout Systems, Inc. and contributors. // Portions ©2008-2010 Apple Inc. All rights reserved. // License: Licensed under MIT license (see license.js) // ========================================================================== /*globals module test ok equals same AB */ var AB; module("Sample Model from an address book app", { setup: function() { // define the application space AB = SC.Application.create({ store: SC.Store.create(SC.Record.fixtures) }); // Describes a single contact detail such as a phone number, address, // email, etc. AB.ContactDetail = SC.Record.extend({ }); // Describes a generic contact. A contact has contact details, which // describe contact info. A contact also has a fullName, which changes // depending on the type. AB.Contact = SC.Record.extend({ details: SC.Record.toMany(AB.ContactDetail) }); AB.ContactGroup = SC.Record.extend({ // creates a computed property that will fetch with a keyname 'contacts' // and params 'group': this. Collection will be setup with newRecord // to create contact records. contacts: SC.Collection.fetch({ inverse: 'group', recordType: 'AB.Contact' }) }); // a generic contact detail must always have a label, kind, and value AB.ContactDetail = SC.Record.extend({ validateLabel: SC.Record.validate(String).required(), validateKind: SC.Record.validate(String).required() }); AB.PhoneNumber = AB.ContactDetail.extend({ kindDefault: 'phone', labelDefault: 'home' }); AB.Contact = SC.Record.extend({ // firstName, lastName, middleName // companyName isCompany: SC.Record.property(Boolean, { defaultValue: NO }), // contact has one or more phones stored in a hash. phones: SC.Collection.inline({ recordType: 'AB.PhoneNumber' }) }); /* IDEA: Every record has an "owner". The owner can be a Store or a Collection. When the record is destroyed or updated, it will notify its owner. A Collection can be inlined, referenced, or fetched. Inlined means the full record data is stored in the parent itself. Referenced means only the primaryKey is stored. Fetched means the collection is loaded from the store dynamically. A Collection can also indicate that it's records are dependent. Dependent records are owned exclusively by the parent record. Deleting parent will delete the collection also. Otherwise deleting the record will remove it from the store only. */ /* hm -- a record could have details stored inline for optimization, but it is not actually owned there. it should just be loaded into the store and treated independently. */ // A contact has contactDetails, which is an array of inlined contact // details. AB.Contact = SC.Record.extend({ firstNameType: String, lastNameType: String, contactDetailsType: SC.Collection.inline({ isDependent: YES, recordType: 'AB.ContactDetail' }), // a contact belongs to one or more groups stored as an array on // the contact. You can change the groups array by replacing the // array. groups: function(key, groups) { // if groups is replaced, write back guids // also, each group record should have it's contacts invalidated. if (groups !== undefined) { this.writeAttribute('groups', groups.getEach('guid')) ; groups.invoke('notifyPropertyChange', 'contacts'); } return this.get('store').records(this.readAttribute('groups')); }.property().cacheable() }); AB.ContactAddress = SC.Record.extend({ descriptionType: String, street1: String, street2: String, city: String, state: String, country: String, // the contact the address belongs to. contact: function() { this.get('store').record(this.readAttribute('contact')); } }); } });