]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | /**\r |
2 | * This class is a base for all id generators. It also provides lookup of id generators by\r | |
3 | * their id.\r | |
4 | * \r | |
5 | * Generally, id generators are used to generate a primary key for new model instances. There\r | |
6 | * are different approaches to solving this problem, so this mechanism has both simple use\r | |
7 | * cases and is open to custom implementations. A {@link Ext.data.Model} requests id generation\r | |
8 | * using the {@link Ext.data.Model#identifier} property.\r | |
9 | *\r | |
10 | * The following types of `identifiers` are provided:\r | |
11 | *\r | |
12 | * * `{@link Ext.data.identifier.Sequential sequential}`\r | |
13 | * * `{@link Ext.data.identifier.Negative negative}`\r | |
14 | * * `{@link Ext.data.identifier.Uuid uuid}`\r | |
15 | *\r | |
16 | * In most cases (other than `uuid`), the server is the only party that can generate\r | |
17 | * authoritative id values. This means that any id generated by an `identifier` should be\r | |
18 | * consider "provisional" and must eventually be reconciled with the server. This makes a\r | |
19 | * `uuid` very attractive as an `identifier` because they are designed to be generated in\r | |
20 | * a distributed manner and therefore never require reconciliation.\r | |
21 | *\r | |
22 | * It is common for id values to be generated as increasing integer values (1, 2, etc.) by\r | |
23 | * the server when records are inserted. A `{@link Ext.data.identifier.Negative negative}`\r | |
24 | * `identifier` may be useful as it generates client-side values of -1, -2, etc.. These\r | |
25 | * values are of the same data type (integer) and so can typically be read by servers\r | |
26 | * using typed languages (such as Java or C#) and easily recognized as provisional.\r | |
27 | *\r | |
28 | * In the end, the choice of `identifier` strategy requires agreement between client and\r | |
29 | * server.\r | |
30 | *\r | |
31 | * # Identity, Type and Shared Generators\r | |
32 | *\r | |
33 | * It is often desirable to share Generators to ensure uniqueness or common configuration.\r | |
34 | * This is done by giving Generator instances an id property by which they can be looked\r | |
35 | * up using the {@link Ext.Factory#dataIdentifier dataIdentifier} method. To configure two {@link Ext.data.Model Model} classes\r | |
36 | * to share one {@link Ext.data.identifier.Sequential sequential} id generator, you simply\r | |
37 | * assign them the same id:\r | |
38 | *\r | |
39 | * Ext.define('MyApp.data.MyModelA', {\r | |
40 | * extend: 'Ext.data.Model',\r | |
41 | * identifier: {\r | |
42 | * type: 'sequential',\r | |
43 | * id: 'foo'\r | |
44 | * }\r | |
45 | * });\r | |
46 | *\r | |
47 | * Ext.define('MyApp.data.MyModelB', {\r | |
48 | * extend: 'Ext.data.Model',\r | |
49 | * identifier: {\r | |
50 | * type: 'sequential',\r | |
51 | * id: 'foo'\r | |
52 | * }\r | |
53 | * });\r | |
54 | *\r | |
55 | * To make this as simple as possible for generator types that are shared by many (or all)\r | |
56 | * Models, the Generator types (such as 'sequential' or 'uuid') are also reserved as\r | |
57 | * generator ids. This is used by the {@link Ext.data.identifier.Uuid} which has an id equal\r | |
58 | * to its type ('uuid'). In other words, the following Models share the same generator:\r | |
59 | *\r | |
60 | * Ext.define('MyApp.data.MyModelX', {\r | |
61 | * extend: 'Ext.data.Model',\r | |
62 | * identifier: 'uuid'\r | |
63 | * });\r | |
64 | *\r | |
65 | * Ext.define('MyApp.data.MyModelY', {\r | |
66 | * extend: 'Ext.data.Model',\r | |
67 | * identifier: 'uuid'\r | |
68 | * });\r | |
69 | *\r | |
70 | * This can be overridden (by specifying the id explicitly), but there is no particularly\r | |
71 | * good reason to do so for this generator type.\r | |
72 | *\r | |
73 | * # Creating Custom Generators\r | |
74 | * \r | |
75 | * An id generator should derive from this class and implement the {@link #generate} method.\r | |
76 | *\r | |
77 | * To register an id generator type, a derived class should provide an `alias` like so:\r | |
78 | *\r | |
79 | * Ext.define('MyApp.data.identifier.Custom', {\r | |
80 | * extend: 'Ext.data.identifier.Generator',\r | |
81 | * alias: 'data.identifier.custom',\r | |
82 | * config: {\r | |
83 | * configProp: 42 // some config property w/default value\r | |
84 | * }\r | |
85 | *\r | |
86 | * generate: function () {\r | |
87 | * return ... // a new id\r | |
88 | * }\r | |
89 | * });\r | |
90 | *\r | |
91 | * Using the custom id generator is then straightforward:\r | |
92 | *\r | |
93 | * Ext.define('MyApp.data.MyModel', {\r | |
94 | * extend: 'Ext.data.Model',\r | |
95 | * identifier: 'custom'\r | |
96 | * });\r | |
97 | * // or...\r | |
98 | *\r | |
99 | * Ext.define('MyApp.data.MyModel', {\r | |
100 | * extend: 'Ext.data.Model',\r | |
101 | * identifier: {\r | |
102 | * type: 'custom',\r | |
103 | * configProp: value\r | |
104 | * }\r | |
105 | * });\r | |
106 | *\r | |
107 | * It is not recommended to mix shared generators with generator configuration. This leads\r | |
108 | * to unpredictable results unless all configurations match (which is also redundant). In\r | |
109 | * such cases, a custom generator with a default id is the best approach.\r | |
110 | *\r | |
111 | * Ext.define('MyApp.data.identifier.Custom', {\r | |
112 | * extend: 'Ext.data.identifier.Sequential',\r | |
113 | * alias: 'data.identifier.custom',\r | |
114 | * \r | |
115 | * config: {\r | |
116 | * id: 'custom',\r | |
117 | * prefix: 'ID_',\r | |
118 | * seed: 1000\r | |
119 | * }\r | |
120 | * });\r | |
121 | *\r | |
122 | * Ext.define('MyApp.data.MyModelX', {\r | |
123 | * extend: 'Ext.data.Model',\r | |
124 | * identifier: 'custom'\r | |
125 | * });\r | |
126 | *\r | |
127 | * Ext.define('MyApp.data.MyModelY', {\r | |
128 | * extend: 'Ext.data.Model',\r | |
129 | * identifier: 'custom'\r | |
130 | * });\r | |
131 | *\r | |
132 | * // the above models share a generator that produces ID_1000, ID_1001, etc..\r | |
133 | *\r | |
134 | */\r | |
135 | Ext.define('Ext.data.identifier.Generator', {\r | |
136 | 'abstract': true,\r | |
137 | \r | |
138 | mixins: [\r | |
139 | 'Ext.mixin.Factoryable'\r | |
140 | ],\r | |
141 | \r | |
142 | alias: 'data.identifier.default', // this is used by Factoryable\r | |
143 | \r | |
144 | factoryConfig: {\r | |
145 | defaultType: 'sequential' // this is not a suitable type to create\r | |
146 | },\r | |
147 | \r | |
148 | /**\r | |
149 | * @property {Boolean} isGenerator\r | |
150 | * `true` in this class to identify an object as an instantiated IdGenerator, or subclass thereof.\r | |
151 | */\r | |
152 | isGenerator: true,\r | |
153 | \r | |
154 | config: {\r | |
155 | /**\r | |
156 | * @cfg {String} id\r | |
157 | * The id for this generator.\r | |
158 | */\r | |
159 | id: null\r | |
160 | },\r | |
161 | \r | |
162 | /**\r | |
163 | * Initializes a new instance.\r | |
164 | * @param {Object} config (optional) Configuration object to be applied to the new instance.\r | |
165 | */\r | |
166 | constructor: function (config) {\r | |
167 | var me = this,\r | |
168 | cache, id;\r | |
169 | \r | |
170 | me.initConfig(config);\r | |
171 | \r | |
172 | id = me.getId();\r | |
173 | if (id) {\r | |
174 | cache = (config && config.cache) || Ext.data.identifier.Generator.all;\r | |
175 | cache[id] = me;\r | |
176 | }\r | |
177 | },\r | |
178 | \r | |
179 | /**\r | |
180 | * Generates and returns the next id. This method must be implemented by the derived\r | |
181 | * class.\r | |
182 | *\r | |
183 | * @return {Number/String} The next id.\r | |
184 | * @method generate\r | |
185 | * @abstract\r | |
186 | */\r | |
187 | \r | |
188 | privates: {\r | |
189 | /**\r | |
190 | * Create a copy of this identifier.\r | |
191 | * @private\r | |
192 | * @return {Ext.data.identifier.Generator} The clone\r | |
193 | */\r | |
194 | clone: function (config) {\r | |
195 | var cfg = this.getInitialConfig();\r | |
196 | cfg = config ? Ext.apply({}, config, cfg) : cfg;\r | |
197 | return new this.self(cfg);\r | |
198 | },\r | |
199 | \r | |
200 | statics: {\r | |
201 | /**\r | |
202 | * @property {Object} all\r | |
203 | * This object is keyed by id to lookup instances.\r | |
204 | * @private\r | |
205 | * @static\r | |
206 | */\r | |
207 | all: {}\r | |
208 | }\r | |
209 | }\r | |
210 | },\r | |
211 | function () {\r | |
212 | var Generator = this,\r | |
213 | Factory = Ext.Factory,\r | |
214 | factory = Factory.dataIdentifier;\r | |
215 | \r | |
216 | // If there is an id property passed we need to lookup that id in the cache. If that\r | |
217 | // produces a cache miss, call the normal factory.\r | |
218 | /**\r | |
219 | * @member Ext.Factory\r | |
220 | * @method dataIdentifier\r | |
221 | * Returns an instance of an ID generator based on the ID you pass in.\r | |
222 | * @param {string} id\r | |
223 | * @return {Object} Ext.data.identifier.* The data identifier\r | |
224 | */\r | |
225 | Factory.dataIdentifier = function (config) {\r | |
226 | var id = Ext.isString(config) ? config : (config && config.id),\r | |
227 | existing = id && ((config && config.cache) || Generator.all)[id];\r | |
228 | \r | |
229 | return existing || factory(config);\r | |
230 | };\r | |
231 | });\r |