/**
* This class is a base for all id generators. It also provides lookup of id generators by
* their id.
*
* Generally, id generators are used to generate a primary key for new model instances. There
* are different approaches to solving this problem, so this mechanism has both simple use
* cases and is open to custom implementations. A {@link Ext.data.Model} requests id generation
* using the {@link Ext.data.Model#identifier} property.
*
* The following types of `identifiers` are provided:
*
* * `{@link Ext.data.identifier.Sequential sequential}`
* * `{@link Ext.data.identifier.Negative negative}`
* * `{@link Ext.data.identifier.Uuid uuid}`
*
* In most cases (other than `uuid`), the server is the only party that can generate
* authoritative id values. This means that any id generated by an `identifier` should be
* consider "provisional" and must eventually be reconciled with the server. This makes a
* `uuid` very attractive as an `identifier` because they are designed to be generated in
* a distributed manner and therefore never require reconciliation.
*
* It is common for id values to be generated as increasing integer values (1, 2, etc.) by
* the server when records are inserted. A `{@link Ext.data.identifier.Negative negative}`
* `identifier` may be useful as it generates client-side values of -1, -2, etc.. These
* values are of the same data type (integer) and so can typically be read by servers
* using typed languages (such as Java or C#) and easily recognized as provisional.
*
* In the end, the choice of `identifier` strategy requires agreement between client and
* server.
*
* # Identity, Type and Shared Generators
*
* It is often desirable to share Generators to ensure uniqueness or common configuration.
* This is done by giving Generator instances an id property by which they can be looked
* up using the {@link Ext.Factory#dataIdentifier dataIdentifier} method. To configure two
* {@link Ext.data.Model Model} classes to share one
* {@link Ext.data.identifier.Sequential sequential} id generator, you simply assign them
* the same id:
*
* Ext.define('MyApp.data.MyModelA', {
* extend: 'Ext.data.Model',
* identifier: {
* type: 'sequential',
* id: 'foo'
* }
* });
*
* Ext.define('MyApp.data.MyModelB', {
* extend: 'Ext.data.Model',
* identifier: {
* type: 'sequential',
* id: 'foo'
* }
* });
*
* To make this as simple as possible for generator types that are shared by many (or all)
* Models, the Generator types (such as 'sequential' or 'uuid') are also reserved as
* generator ids. This is used by the {@link Ext.data.identifier.Uuid} which has an id equal
* to its type ('uuid'). In other words, the following Models share the same generator:
*
* Ext.define('MyApp.data.MyModelX', {
* extend: 'Ext.data.Model',
* identifier: 'uuid'
* });
*
* Ext.define('MyApp.data.MyModelY', {
* extend: 'Ext.data.Model',
* identifier: 'uuid'
* });
*
* This can be overridden (by specifying the id explicitly), but there is no particularly
* good reason to do so for this generator type.
*
* # Creating Custom Generators
*
* An id generator should derive from this class and implement the {@link #generate} method.
*
* To register an id generator type, a derived class should provide an `alias` like so:
*
* Ext.define('MyApp.data.identifier.Custom', {
* extend: 'Ext.data.identifier.Generator',
* alias: 'data.identifier.custom',
* config: {
* configProp: 42 // some config property w/default value
* }
*
* generate: function () {
* return ... // a new id
* }
* });
*
* Using the custom id generator is then straightforward:
*
* Ext.define('MyApp.data.MyModel', {
* extend: 'Ext.data.Model',
* identifier: 'custom'
* });
* // or...
*
* Ext.define('MyApp.data.MyModel', {
* extend: 'Ext.data.Model',
* identifier: {
* type: 'custom',
* configProp: value
* }
* });
*
* It is not recommended to mix shared generators with generator configuration. This leads
* to unpredictable results unless all configurations match (which is also redundant). In
* such cases, a custom generator with a default id is the best approach.
*
* Ext.define('MyApp.data.identifier.Custom', {
* extend: 'Ext.data.identifier.Sequential',
* alias: 'data.identifier.custom',
*
* config: {
* id: 'custom',
* prefix: 'ID_',
* seed: 1000
* }
* });
*
* Ext.define('MyApp.data.MyModelX', {
* extend: 'Ext.data.Model',
* identifier: 'custom'
* });
*
* Ext.define('MyApp.data.MyModelY', {
* extend: 'Ext.data.Model',
* identifier: 'custom'
* });
*
* // the above models share a generator that produces ID_1000, ID_1001, etc..
*
*/
Ext.define('Ext.data.identifier.Generator', {
'abstract': true,
mixins: [
'Ext.mixin.Factoryable'
],
alias: 'data.identifier.default', // this is used by Factoryable
factoryConfig: {
defaultType: 'sequential' // this is not a suitable type to create
},
/**
* @property {Boolean} isGenerator
* `true` in this class to identify an object as an instantiated IdGenerator, or subclass
* thereof.
*/
isGenerator: true,
config: {
/**
* @cfg {String} id
* The id for this generator.
*/
id: null
},
/**
* Initializes a new instance.
* @param {Object} config (optional) Configuration object to be applied to the new instance.
*/
constructor: function(config) {
var me = this,
id;
me.initConfig(config);
id = me.getId();
if (id) {
Ext.data.identifier.Generator.all[id] = me;
}
},
/**
* Generates and returns the next id. This method must be implemented by the derived
* class.
*
* @return {Number/String} The next id.
* @method generate
* @abstract
*/
privates: {
/**
* Create a copy of this identifier.
* @private
* @return {Ext.data.identifier.Generator} The clone
*/
clone: function(config) {
var cfg = this.getInitialConfig();
cfg = config ? Ext.apply({}, config, cfg) : cfg;
return new this.self(cfg);
},
statics: {
/**
* @property {Object} all
* This object is keyed by id to lookup instances.
* @private
* @static
*/
all: {}
}
}
}, function() {
var Generator = this,
Factory = Ext.Factory,
factory = Factory.dataIdentifier;
// If there is an id property passed we need to lookup that id in the cache. If that
// produces a cache miss, call the normal factory.
/**
* @member Ext.Factory
* @method dataIdentifier
* Returns an instance of an ID generator based on the ID you pass in.
* @param {String/Object} config The config object or `id` to lookup.
* @return {Object} Ext.data.identifier.* The data identifier
*/
Factory.dataIdentifier = function(config) {
var id = Ext.isString(config) ? config : (config && config.id),
existing = id && Generator.all[id];
return existing || factory(config);
};
});