Class: SC.Record


Extends SC.Object.

A Record is the core model class in SproutCore. It is analogous to NSManagedObject in Core Data and EOEnterpriseObject in the Enterprise Objects Framework (aka WebObjects), or ActiveRecord::Base in Rails.

To create a new model class, in your SproutCore workspace, do:

$ sc-gen model MyApp.MyModel

This will create MyApp.MyModel in clients/my_app/models/my_model.js.

The core attributes hash is used to store the values of a record in a format that can be easily passed to/from the server. The values should generally be stored in their raw string form. References to external records should be stored as primary keys.

Normally you do not need to work with the attributes hash directly. Instead you should use get/set on normal record properties. If the property is not defined on the object, then the record will check the attributes hash instead.

You can bulk update attributes from the server using the updateAttributes() method.

Polymorphic Records

SC.Record also supports polymorphism, which allows subclasses of a record type to share a common identity. Polymorphism is similar to inheritance (i.e. a polymorphic subclass inherits its parents properties), but differs in that polymorphic subclasses can be considered to be "equal" to each other and their superclass. This means that any memmber of the polymorphic class group should be able to stand in for any other member.

These examples may help identify the difference. First, let's look at the classic inheritance model,

// This is the "root" class. All subclasses of MyApp.Person will be unique from MyApp.Person.
MyApp.Person = SC.Record.extend({});

// As a subclass, MyApp.Female inherits from a MyApp.Person, but is not "equal" to it.
MyApp.Female = MyApp.Person.extend({
  isFemale: true
});

// As a subclass, MyApp.Male inherits from a MyApp.Person, but is not "equal" to it.
MyApp.Male = MyApp.Person.extend({
  isMale: true
});

// Load two unique records into the store.
MyApp.store.createRecord(MyApp.Female, { guid: '1' });
MyApp.store.createRecord(MyApp.Male, { guid: '2' });

// Now we can see that these records are isolated from each other.
var female = MyApp.store.find(MyApp.Person, '1'); // Returns an SC.Record.EMPTY record.
var male = MyApp.store.find(MyApp.Person, '2'); // Returns an SC.Record.EMPTY record.

// These records are MyApp.Person only.
SC.kindOf(female, MyApp.Female); // false
SC.kindOf(male, MyApp.Male); // false

Next, let's make MyApp.Person a polymorphic class,

// This is the "root" polymorphic class. All subclasses of MyApp.Person will be able to stand-in as a MyApp.Person.
MyApp.Person = SC.Record.extend({
  isPolymorphic: true
});

// As a polymorphic subclass, MyApp.Female is "equal" to a MyApp.Person.
MyApp.Female = MyApp.Person.extend({
  isFemale: true
});

// As a polymorphic subclass, MyApp.Male is "equal" to a MyApp.Person.
MyApp.Male = MyApp.Person.extend({
  isMale: true
});

// Load two unique records into the store.
MyApp.store.createRecord(MyApp.Female, { guid: '1' });
MyApp.store.createRecord(MyApp.Male, { guid: '2' });

// Now we can see that these records are in fact "equal" to each other. Which means that if we
// search for "people", we will get "males" & "females".
var female = MyApp.store.find(MyApp.Person, '1'); // Returns record.
var male = MyApp.store.find(MyApp.Person, '2'); // Returns record.

// These records are MyApp.Person as well as their unique subclass.
SC.kindOf(female, MyApp.Female); // true
SC.kindOf(male, MyApp.Male); // true

Defined in: record.js

See:
SC.RecordAttribute
Since:
SproutCore 1.0

Field Summary

Fields borrowed from SC.Object:
concatenatedProperties, isObject, nextProperty, object, property, target, toInvalidate
Fields borrowed from SC.Observable:
isObservable

Class Methods

Instance Methods

Field Detail

SC.Record.BAD_STATE_ERROR SC.Error

Error for when you try to modify a record while it is in a bad state.

SC.Record.BUSY Number

Generic state for records that have been submitted to data source

Use a logical AND (single &) to test record status

Default value:
0x0800
SC.Record.BUSY_COMMITTING Number

State for records that have been modified and submitted to server

Use a logical AND (single &) to test record status

Default value:
0x0810
SC.Record.BUSY_CREATING Number

State for new records that were created and submitted to the server; waiting on response from server

Use a logical AND (single &) to test record status

Default value:
0x0808
SC.Record.BUSY_DESTROYING Number

State for records that have been destroyed and submitted to server

Use a logical AND (single &) to test record status

Default value:
0x0840
SC.Record.BUSY_ERROR SC.Error
Error for when you try to modify a record that is currently busy
SC.Record.BUSY_LOADING Number

State for records that are still loading data from the server

Use a logical AND (single &) to test record status

Default value:
0x0804
SC.Record.BUSY_REFRESH Number

State for records that have requested a refresh from the server.

Use a logical AND (single &) to test record status.

Default value:
0x0820
SC.Record.BUSY_REFRESH_CLEAN Number

State for records that have requested a refresh from the server.

Use a logical AND (single &) to test record status

Default value:
0x0821
SC.Record.BUSY_REFRESH_DIRTY Number

State for records that have requested a refresh from the server.

Use a logical AND (single &) to test record status

Default value:
0x0822
SC.Record.CLEAN Number

Generic state for records with no local changes.

Use a logical AND (single &) to test record status

Default value:
0x0001
SC.Record.DESTROYED Number

Generic state for records that have been destroyed

Use a logical AND (single &) to test record status

Default value:
0x0400
SC.Record.DESTROYED_CLEAN Number

State for records that have been destroyed and committed to server

Use a logical AND (single &) to test record status

Default value:
0x0401
SC.Record.DESTROYED_DIRTY Number

State for records that have been destroyed but not yet committed to server

Use a logical AND (single &) to test record status

Default value:
0x0402
SC.Record.DIRTY Number

Generic state for records with local changes.

Use a logical AND (single &) to test record status

Default value:
0x0002
SC.Record.EMPTY Number

State for records that are still loaded.

A record instance should never be in this state. You will only run into it when working with the low-level data hash API on SC.Store. Use a logical AND (single &) to test record status

Default value:
0x0100
SC.Record.ERROR Number

State for records in an error state.

Use a logical AND (single &) to test record status

Default value:
0x1000
SC.Record.fixtures
Default fixtures instance for use in applications.
Defined in: fixtures.js.
SC.Record.GENERIC_ERROR SC.Error
Generic unknown record error
SC.Record.ignoreUnknownProperties Boolean

Whether to ignore unknown properties when they are being set on the record object. This is useful if you want to strictly enforce the model schema and not allow dynamically expanding it by setting new unknown properties

Default value:
NO
isParentRecord Boolean
If you have nested records
Default value:
NO
SC.Record.isPolymorphic Boolean

If true, then searches for records of this type will return subclass instances. For example:

Person = SC.Record.extend(); Person.isPolymorphic = true;

Male = Person.extend(); Female = Person.extend();

Using SC.Store#find, or a toOne or toMany relationship on Person will then return records of
type Male and Female. Polymorphic record types must have unique GUIDs across all subclasses.
Default value:
NO
isRecord Boolean
Walk like a duck
Default value:
YES
nestedRecordNamespace String
The namespace which to retrieve the childRecord Types from
Default value:
null
SC.Record.NOT_FOUND_ERROR SC.Error
Error for when you attempt to locate a record that is not found
primaryKey String

This is the primary key used to distinguish records. If the keys match, the records are assumed to be identical.

Default value:
'guid'
SC.Record.READY Number

Generic state for records that are loaded and ready for use

Use a logical AND (single &) to test record status

Default value:
0x0200
SC.Record.READY_CLEAN Number

State for records that are loaded and ready for use with no local changes

Use a logical AND (single &) to test record status

Default value:
0x0201
SC.Record.READY_DIRTY Number

State for records that are loaded and ready for use with local changes

Use a logical AND (single &) to test record status

Default value:
0x0202
SC.Record.READY_NEW Number

State for records that are new - not yet committed to server

Use a logical AND (single &) to test record status

Default value:
0x0203
SC.Record.RECORD_EXISTS_ERROR SC.Error
Error for when you try to create a new record that already exists.
relationships Array

If set, this should be an array of active relationship objects that need to be notified whenever the underlying record properties change. Currently this is only used by toMany relationships, but you could possibly patch into this yourself also if you are building your own relationships.

Note this must be a regular Array - NOT any object implementing SC.Array.

Default value:
null
store SC.Store

The store that owns this record. All changes will be buffered into this store and committed to the rest of the store chain through here.

This property is set when the record instance is created and should not be changed or else it will break the record behavior.

Default value:
null
storeKey Number

This is the store key for the record, it is used to link it back to the dataHash. If a record is reused, this value will be replaced.

You should not edit this store key but you may sometimes need to refer to this store key when implementing a Server object.

Default value:
null

Class Method Detail

attr(type, opts)

Helper method returns a new SC.RecordAttribute instance to map a simple value or to-one relationship. At the very least, you should pass the type class you expect the attribute to have. You may pass any additional options as well.

Use this helper when you define SC.Record subclasses.

MyApp.Contact = SC.Record.extend({
  firstName: SC.Record.attr(String, { isRequired: YES })
});
Parameters:
type Class
the attribute type
opts Hash
the options for the attribute
Returns:
SC.RecordAttribute
created instance
fetch(recordType, opts)

Returns an SC.RecordAttribute that describes a fetched attribute. When you reference this attribute, it will return an SC.RecordArray that uses the type as the fetch key and passes the attribute value as a param.

Use this helper when you define SC.Record subclasses.

MyApp.Group = SC.Record.extend({
  contacts: SC.Record.fetch('MyApp.Contact')
});
Parameters:
recordType SC.Record|String
The type of records to load
opts Hash
the options for the attribute
Returns:
SC.RecordAttribute
created instance
find(store, id)
Returns a record with the named ID in store.
Parameters:
store SC.Store
the store
id String
the record id or a query
Returns:
SC.Record
record instance
storeKeyExists(id)

Given a primaryKey value for the record, returns the associated storeKey. As opposed to storeKeyFor() however, this method will NOT generate a new storeKey but returned undefined.

Parameters:
id String
a record id
Returns:
Number
a storeKey.
storeKeyFor(id)

Given a primaryKey value for the record, returns the associated storeKey. If the primaryKey has not been assigned a storeKey yet, it will be added.

For the inverse of this method see SC.Store.idFor() and SC.Store.recordTypeFor().

Parameters:
id String
a record id
Returns:
Number
a storeKey.
storeKeysById()

Returns all storeKeys mapped by Id for this record type. This method is used mostly by the SC.Store and the Record to coordinate. You will rarely need to call this method yourself.

Note that for polymorpic record classes, all store keys are kept on the top-most polymorphic superclass. This ensures that store key by id requests at any level return only the one unique store key.

See:
SC.Record.storeKeysById
toMany(recordType, opts)

Will return one of the following:

  1. SC.ManyAttribute that describes a record array backed by an array of guids stored in the underlying JSON.
  2. SC.ChildrenAttribute that describes a record array backed by a array of hashes.

    You can edit the contents of this relationship.

    For SC.ManyAttribute, If you set the inverse and isMaster: NO key, then editing this array will modify the underlying data, but the inverse key on the matching record will also be edited and that record will be marked as needing a change.

Parameters:
recordType SC.Record|String
The type of record to create
opts Hash
the options for the attribute
Returns:
SC.ManyAttribute|SC.ChildrenAttribute
created instance
toOne(recordType, opts)

Will return one of the following:

  1. SC.SingleAttribute that converts the underlying ID to a single record. If you modify this property, it will rewrite the underlying ID. It will also modify the inverse of the relationship, if you set it.
  2. SC.ChildAttribute that you can edit the contents of this relationship.
Parameters:
recordType SC.Record|String
the type of the record to create
opts Hash
additional options
Returns:
SC.SingleAttribute|SC.ChildAttribute
created instance

Instance Method Detail

attributes()

This will return the raw attributes that you can edit directly. If you make changes to this hash, be sure to call beginEditing() before you get the attributes and endEditing() afterwards.

beginEditing()

Defers notification of record changes until you call a matching endEditing() method. This method is called automatically whenever you set an attribute, but you can call it yourself to group multiple changes.

Calls to beginEditing() and endEditing() can be nested.

Returns:
SC.Record
receiver
commitRecord(params, recordOnly, callback)

Lets you commit this specific record to the store which will trigger the appropriate methods in the data source for you.

Parameters:
params Hash
optional additional params that will passed down to the data source
recordOnly boolean
optional param if you want to only commit a single record if it has a parent.
callback Function
optional callback that the store will fire once the datasource finished committing
Returns:
SC.Record
receiver
createNestedRecord(recordType, hash, psk, path)
Creates a new nested record instance.
Parameters:
recordType SC.Record
The type of the nested record to create.
hash Hash
The hash of attributes to apply to the child record. (may be null)
psk
path
Returns:
SC.Record
the nested record created
destroy(recordOnly)

Deletes the record along with any dependent records. This will mark the records destroyed in the store as well as changing the isDestroyed property on the record to YES. If this is a new record, this will avoid creating the record in the first place.

Parameters:
recordOnly boolean
optional param if you want to only THIS record even if it is a child record.
Returns:
SC.Record
receiver
endEditing(key)

Notifies the store of record changes if this matches a top level call to beginEditing(). This method is called automatically whenever you set an attribute, but you can call it yourself to group multiple changes.

Calls to beginEditing() and endEditing() can be nested.

Parameters:
key String
key that changed (optional)
Returns:
SC.Record
receiver
errorObject()

Returns the current error object only if the record is in an error state. If no explicit error object has been set, returns SC.Record.GENERIC_ERROR.

errorValue()

Returns the receiver if the record is in an error state. Returns null otherwise.

generateIdForChild(childRecord)

Override this function if you want to have a special way of creating ids for your child records

Parameters:
childRecord SC.Record
Returns:
String
the id generated
id(key, value)

Returns the id for the record instance. The id is used to uniquely identify this record instance from all others of the same type. If you have a primaryKey set on this class, then the id will be the value of the primaryKey` property on the underlying JSON hash.

Parameters:
key
value
isDestroyed()
YES when the record has been destroyed
isEditable(key, value)

YES when the record is in an editable state. You can use this property to quickly determine whether attempting to modify the record would raise an exception or not.

This property is both readable and writable. Note however that if you set this property to YES but the status of the record is anything but SC.Record.READY, the return value of this property may remain NO.

Parameters:
key
value
isError()

Returns YES whenever the status is SC.Record.ERROR. This will allow you to put the UI into an error state.

isLoaded()

YES when the record's contents have been loaded for the first time. You can use this to quickly determine if the record is ready to display.

isNestedRecord()
Whether or not this is a nested Record.
normalize(includeNull)

Normalizing a record will ensure that the underlying hash conforms to the record attributes such as their types (transforms) and default values.

This method will write the conforming hash to the store and return the materialized record.

By normalizing the record, you can use .attributes() and be assured that it will conform to the defined model. For example, this can be useful in the case where you need to send a JSON representation to some server after you have used .createRecord(), since this method will enforce the 'rules' in the model such as their types and default values. You can also include null values in the hash with the includeNull argument.

Parameters:
includeNull Boolean
will write empty (null) attributes
Returns:
SC.Record
the normalized record
parentRecord()
The parent record if this is a nested record.
propagateToAggregates()

This will also ensure that any aggregate records are also marked dirty if this record changes.

Should not have to be called manually.

readAttribute(key)

Reads the raw attribute from the underlying data hash. This method does not transform the underlying attribute at all.

Parameters:
key String
the attribute you want to read
Returns:
Object
the value of the key, or undefined if it doesn't exist
readOnlyAttributes()

This will return the raw attributes that you cannot edit directly. It is useful if you want to efficiently look at multiple attributes in bulk. If you would like to edit the attributes, see the attributes property instead.

recordDidChange(key)

You can invoke this method anytime you need to make the record as dirty. This will cause the record to be committed when you commitChanges() on the underlying store.

If you use the writeAttribute() primitive, this method will be called for you.

If you pass the key that changed it will ensure that observers are fired only once for the changed property instead of allPropertiesDidChange()

Parameters:
key String
key that changed (optional)
Returns:
SC.Record
receiver
refresh(recordOnly, callback)

Refresh the record from the persistent store. If the record was loaded from a persistent store, then the store will be asked to reload the record data from the server. If the record is new and exists only in memory then this call will have no effect.

Parameters:
recordOnly boolean
optional param if you want to only THIS record even if it is a child record.
callback Function
optional callback that will fire when request finishes
Returns:
SC.Record
receiver
registerNestedRecord(value, key, path)

Registers a child record with this parent record.

If the parent already knows about the child record, return the cached instance. If not, create the child record instance and add it to the child record cache.

Parameters:
value Hash
The hash of attributes to apply to the child record.
key Integer
The store key that we are asking for
path String
The property path of the child record
Returns:
SC.Record
the child record that was registered
status()

All records generally have a life cycle as they are created or loaded into memory, modified, committed and finally destroyed. This life cycle is managed by the status property on your record.

The status of a record is modelled as a finite state machine. Based on the current state of the record, you can determine which operations are currently allowed on the record and which are not.

In general, a record can be in one of five primary states: SC.Record.EMPTY, SC.Record.BUSY, SC.Record.READY, SC.Record.DESTROYED, SC.Record.ERROR. These are all described in more detail in the class mixin (below) where they are defined.

storeDidChangeProperties(statusOnly, key)

Called by the store whenever the underlying data hash has changed. This will notify any observers interested in data hash properties that they have changed.

Parameters:
statusOnly Boolean
changed
key String
that changed (optional)
Returns:
SC.Record
receiver
toJSON()
unknownProperty(key, value)

If you try to get/set a property not defined by the record, then this method will be called. It will try to get the value from the set of attributes.

This will also check is ignoreUnknownProperties is set on the recordType so that they will not be written to dataHash unless explicitly defined in the model schema.

Parameters:
key String
the attribute being get/set
value Object
the value to set the key to, if present
Returns:
Object
the value
unregisterNestedRecord(path)

Unregisters a child record from its parent record.

Since accessing a child (nested) record creates a new data hash for the child and caches the child record and its relationship to the parent record, it's important to clear those caches when the child record is overwritten or removed. This function tells the store to remove the child record from the store's various child record caches.

You should not need to call this function directly. Simply setting the child record property on the parent to a different value will cause the previous child record to be unregistered.

Parameters:
path String
The property path of the child record.
writeAttribute(key, value, ignoreDidChange)

Updates the passed attribute with the new value. This method does not transform the value at all. If instead you want to modify an array or hash already defined on the underlying json, you should instead get an editable version of the attribute using editableAttribute().

Parameters:
key String
the attribute you want to read
value Object
the value you want to write
ignoreDidChange Boolean
only set if you do NOT want to flag record as dirty
Returns:
SC.Record
receiver
Documentation generated by JsDoc Toolkit 2.4.0 on Wed Apr 08 2015 10:02:21 GMT-0600 (CST)