Defining your data model

When planning the data component of any particular application, we always start with a data model. A data model is just a diagram or description that defines the record types and their relationships. These record types, or models, will closely map the types of data we expect to bring into the application. So, for instance, if we are going to load student record data, we will likely want a MyApp.Student model.

Let's look at an example of how a data model for a calendaring application may start out:

Defining your data model

This data model is about as simple as it can get. We have calendar records, each of which has zero or more event records. In turn, each event record has one calendar record. We'll get to coding the record relationships soon, but first we need to be able to define the models and their attributes for our application.

To create record classes we simply extend SC.Record.

For example:

/** @class
  A calendar record.
*/
MyApp.Calendar = SC.Record.extend({

});

/** @class
  An event in a calendar.
*/
MyApp.Event = SC.Record.extend({

});

After creating a record class, the next step is to indicate the attributes of the record. When defining records, we differentiate between the attributes, which are properties backed by the underlying data hash and normal object properties like we learned in the Chapter 2, The Runtime Environment.

To define an attribute property for the record, we use an instance of SC.RecordAttribute, which is easily created using the attr helper method of SC.Record. This helper method accepts the type of the attribute as the first argument and a hash of options for the attribute as the second argument.

For example:

MyApp.Calendar = SC.Record.extend({

  // Title of the calendar.
  title: SC.Record.attr(String, {
    defaultValue: "New Calendar"  
  })

});

As you can see in the example, we declared that the title attribute data is of String type and used the defaultValue option to provide a default value for all the newly created MyApp.Calendar records. Because we specified the type as String in this case, when accessing the title value of an individual MyApp.Calendar record, we will get a string value back. This may seem obvious because the attribute in the data hash is most certainly a string itself, but what may not be obvious is how SC.RecordAttribute can transform any simple attribute value into a complex type.

Note

Besides the String attribute type, SproutCore also includes Number, Boolean, Object, Array, Date, and SC.DateTime attribute types.

Here is an example where the value in the data hash is not of the same type as the value returned by the attribute:

/** @class
  An event in a calendar.
*/
MyApp.Event = SC.Record.extend({

  // Start time of the event.
  startAt: SC.Record.attr(SC.DateTime, {
    format: '%d/%m/%Y %H:%M:%S'
  })

});

In this example, the record's startAt property is of type SC.DateTime, but the property is just a proxy for the real value in the data hash which will not be of SC.DateTime type. Remember that the underlying data hash should only contain directly serializeable values so that we can convert them to JSON, XML, or some other format in order to be sent to the remote data source. In this case, the stored value will be a string and when the startAt property is requested, the string from the data hash will be transformed into an SC.DateTime object. Likewise, when startAt is set to a new SC.DateTime object, it will be transformed into a string and stored in the underlying data hash.

Before we continue, there are two common options you should know about when defining attributes. The first is isEditable, which, when set to false, will prevent the attribute from being changed. If an attribute is not editable, any attempts to modify it on the client will be ignored, which is a useful way to indicate that the remote data store is the only source of truth for certain attributes.

The second option is key, which allows you to change the name of the attribute looked up in the underlying data hash. By default, the data hash key is expected to be the same as the property name, but we can use the key option in order to name the property one thing and have it backed by an attribute named something else This is useful when the remote data source uses attributes that are unwieldy or don't match the conventions for JavaScript property names. For example, Ruby and Python servers will often use snake case property names (for example, my_variable) while most JavaScript programmers prefer camel case (for example, myVariable). Although we could rename all the attributes when we deserialize the incoming data or eschew the JavaScript conventions and name our properties to whatever matches the raw data, it's simple enough just to set the appropriate key and so, we often do just that.

For example:

// …

userRole: SC.Record.attr(Number, {
  
  // This attribute cannot be changed in the client.
  isEditable: false,

  // The actual name of the attribute in the data hash. 
  key: 'user_role_val'

})

// … 

Finally, there is the matter of an important attribute shared by all records: the primary key. As you probably know, each record in a database must have a unique primary key and SproutCore records in the store are no different. However, the way SC.Record uses primary keys tends to throw people off at first. For one, we do not create an attribute for the primary key of the record. This is because the primary key attribute of all records is already defined by SC.Record and it is id, which is effectively the same as the following:

// …

id: SC.Record.attr(String, {
  key: 'guid'
}),

// …

Therefore, if the primary key name in the data we load is guid, we wouldn't have to make any changes. However, if it is something different, we can change the key used by id by setting the primaryKey property.

For instance, if the primary key attribute in the data for our previous MyApp.Calendar records was _id, our record would look like the following:

MyApp.Calendar = SC.Record.extend({

  // Title of the calendar.
  title: SC.Record.attr(String, {
    defaultValue: "New Calendar"
  }),

  // The primary key attribute in the data hash is '_id'.
  primaryKey: '_id'

});

Because the primaryKey value can be set as per the record class, we can actually work with records loaded from different APIs without having to remember what the specific primary key attribute's name is elsewhere in the application. For example, to get the primary key value of any record we always use the following code line:

var id = aRecord.get('id'),
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.212.71