Upgrade to ExtJS 4.0.7 - Released 10/19/2011
[extjs.git] / src / data / Operation.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @author Ed Spencer
17  *
18  * Represents a single read or write operation performed by a {@link Ext.data.proxy.Proxy Proxy}. Operation objects are
19  * used to enable communication between Stores and Proxies. Application developers should rarely need to interact with
20  * Operation objects directly.
21  *
22  * Several Operations can be batched together in a {@link Ext.data.Batch batch}.
23  */
24 Ext.define('Ext.data.Operation', {
25     /**
26      * @cfg {Boolean} synchronous
27      * True if this Operation is to be executed synchronously. This property is inspected by a
28      * {@link Ext.data.Batch Batch} to see if a series of Operations can be executed in parallel or not.
29      */
30     synchronous: true,
31
32     /**
33      * @cfg {String} action
34      * The action being performed by this Operation. Should be one of 'create', 'read', 'update' or 'destroy'.
35      */
36     action: undefined,
37
38     /**
39      * @cfg {Ext.util.Filter[]} filters
40      * Optional array of filter objects. Only applies to 'read' actions.
41      */
42     filters: undefined,
43
44     /**
45      * @cfg {Ext.util.Sorter[]} sorters
46      * Optional array of sorter objects. Only applies to 'read' actions.
47      */
48     sorters: undefined,
49
50     /**
51      * @cfg {Ext.util.Grouper} group
52      * Optional grouping configuration. Only applies to 'read' actions where grouping is desired.
53      */
54     group: undefined,
55
56     /**
57      * @cfg {Number} start
58      * The start index (offset), used in paging when running a 'read' action.
59      */
60     start: undefined,
61
62     /**
63      * @cfg {Number} limit
64      * The number of records to load. Used on 'read' actions when paging is being used.
65      */
66     limit: undefined,
67
68     /**
69      * @cfg {Ext.data.Batch} batch
70      * The batch that this Operation is a part of.
71      */
72     batch: undefined,
73
74     /**
75      * @cfg {Function} callback
76      * Function to execute when operation completed.  Will be called with the following parameters:
77      *
78      * - records : Array of Ext.data.Model objects.
79      * - operation : The Ext.data.Operation itself.
80      * - success : True when operation completed successfully.
81      */
82     callback: undefined,
83
84     /**
85      * @cfg {Object} scope
86      * Scope for the {@link #callback} function.
87      */
88     scope: undefined,
89
90     /**
91      * @property {Boolean} started
92      * Read-only property tracking the start status of this Operation. Use {@link #isStarted}.
93      * @private
94      */
95     started: false,
96
97     /**
98      * @property {Boolean} running
99      * Read-only property tracking the run status of this Operation. Use {@link #isRunning}.
100      * @private
101      */
102     running: false,
103
104     /**
105      * @property {Boolean} complete
106      * Read-only property tracking the completion status of this Operation. Use {@link #isComplete}.
107      * @private
108      */
109     complete: false,
110
111     /**
112      * @property {Boolean} success
113      * Read-only property tracking whether the Operation was successful or not. This starts as undefined and is set to true
114      * or false by the Proxy that is executing the Operation. It is also set to false by {@link #setException}. Use
115      * {@link #wasSuccessful} to query success status.
116      * @private
117      */
118     success: undefined,
119
120     /**
121      * @property {Boolean} exception
122      * Read-only property tracking the exception status of this Operation. Use {@link #hasException} and see {@link #getError}.
123      * @private
124      */
125     exception: false,
126
127     /**
128      * @property {String/Object} error
129      * The error object passed when {@link #setException} was called. This could be any object or primitive.
130      * @private
131      */
132     error: undefined,
133
134     /**
135      * @property {RegExp} actionCommitRecordsRe
136      * The RegExp used to categorize actions that require record commits.
137      */
138     actionCommitRecordsRe: /^(?:create|update)$/i,
139
140     /**
141      * @property {RegExp} actionSkipSyncRe
142      * The RegExp used to categorize actions that skip local record synchronization. This defaults
143      * to match 'destroy'.
144      */
145     actionSkipSyncRe: /^destroy$/i,
146
147     /**
148      * Creates new Operation object.
149      * @param {Object} config (optional) Config object.
150      */
151     constructor: function(config) {
152         Ext.apply(this, config || {});
153     },
154
155     /**
156      * This method is called to commit data to this instance's records given the records in
157      * the server response. This is followed by calling {@link Ext.data.Model#commit} on all
158      * those records (for 'create' and 'update' actions).
159      *
160      * If this {@link #action} is 'destroy', any server records are ignored and the
161      * {@link Ext.data.Model#commit} method is not called.
162      *
163      * @param {Ext.data.Model[]} serverRecords An array of {@link Ext.data.Model} objects returned by
164      * the server.
165      * @markdown
166      */
167     commitRecords: function (serverRecords) {
168         var me = this,
169             mc, index, clientRecords, serverRec, clientRec;
170
171         if (!me.actionSkipSyncRe.test(me.action)) {
172             clientRecords = me.records;
173
174             if (clientRecords && clientRecords.length) {
175                 mc = Ext.create('Ext.util.MixedCollection', true, function(r) {return r.getId();});
176                 mc.addAll(clientRecords);
177
178                 for (index = serverRecords ? serverRecords.length : 0; index--; ) {
179                     serverRec = serverRecords[index];
180                     clientRec = mc.get(serverRec.getId());
181
182                     if (clientRec) {
183                         clientRec.beginEdit();
184                         clientRec.set(serverRec.data);
185                         clientRec.endEdit(true);
186                     }
187                 }
188
189                 if (me.actionCommitRecordsRe.test(me.action)) {
190                     for (index = clientRecords.length; index--; ) {
191                         clientRecords[index].commit();
192                     }
193                 }
194             }
195         }
196     },
197
198     /**
199      * Marks the Operation as started.
200      */
201     setStarted: function() {
202         this.started = true;
203         this.running = true;
204     },
205
206     /**
207      * Marks the Operation as completed.
208      */
209     setCompleted: function() {
210         this.complete = true;
211         this.running  = false;
212     },
213
214     /**
215      * Marks the Operation as successful.
216      */
217     setSuccessful: function() {
218         this.success = true;
219     },
220
221     /**
222      * Marks the Operation as having experienced an exception. Can be supplied with an option error message/object.
223      * @param {String/Object} error (optional) error string/object
224      */
225     setException: function(error) {
226         this.exception = true;
227         this.success = false;
228         this.running = false;
229         this.error = error;
230     },
231
232     /**
233      * Returns true if this Operation encountered an exception (see also {@link #getError})
234      * @return {Boolean} True if there was an exception
235      */
236     hasException: function() {
237         return this.exception === true;
238     },
239
240     /**
241      * Returns the error string or object that was set using {@link #setException}
242      * @return {String/Object} The error object
243      */
244     getError: function() {
245         return this.error;
246     },
247
248     /**
249      * Returns an array of Ext.data.Model instances as set by the Proxy.
250      * @return {Ext.data.Model[]} Any loaded Records
251      */
252     getRecords: function() {
253         var resultSet = this.getResultSet();
254
255         return (resultSet === undefined ? this.records : resultSet.records);
256     },
257
258     /**
259      * Returns the ResultSet object (if set by the Proxy). This object will contain the {@link Ext.data.Model model}
260      * instances as well as meta data such as number of instances fetched, number available etc
261      * @return {Ext.data.ResultSet} The ResultSet object
262      */
263     getResultSet: function() {
264         return this.resultSet;
265     },
266
267     /**
268      * Returns true if the Operation has been started. Note that the Operation may have started AND completed, see
269      * {@link #isRunning} to test if the Operation is currently running.
270      * @return {Boolean} True if the Operation has started
271      */
272     isStarted: function() {
273         return this.started === true;
274     },
275
276     /**
277      * Returns true if the Operation has been started but has not yet completed.
278      * @return {Boolean} True if the Operation is currently running
279      */
280     isRunning: function() {
281         return this.running === true;
282     },
283
284     /**
285      * Returns true if the Operation has been completed
286      * @return {Boolean} True if the Operation is complete
287      */
288     isComplete: function() {
289         return this.complete === true;
290     },
291
292     /**
293      * Returns true if the Operation has completed and was successful
294      * @return {Boolean} True if successful
295      */
296     wasSuccessful: function() {
297         return this.isComplete() && this.success === true;
298     },
299
300     /**
301      * @private
302      * Associates this Operation with a Batch
303      * @param {Ext.data.Batch} batch The batch
304      */
305     setBatch: function(batch) {
306         this.batch = batch;
307     },
308
309     /**
310      * Checks whether this operation should cause writing to occur.
311      * @return {Boolean} Whether the operation should cause a write to occur.
312      */
313     allowWrite: function() {
314         return this.action != 'read';
315     }
316 });