/** * In-memory proxy. This proxy simply uses a local variable for data storage/retrieval, so its * contents are lost on every page refresh. * * Usually this Proxy isn't used directly, serving instead as a helper to a * {@link Ext.data.Store Store} where a reader is required to load data. For example, say we have * a Store for a User model and have some inline data we want to load, but this data isn't in quite * the right format: we can use a MemoryProxy with a JsonReader to read it into our Store: * * // this is the model we will be using in the store * Ext.define('User', { * extend: 'Ext.data.Model', * fields: [ * { name: 'id', type: 'int' }, * { name: 'name', type: 'string' }, * { name: 'phone', type: 'string', mapping: 'phoneNumber' } * ] * }); * * // this data does not line up to our model fields - the phone field is called phoneNumber * var data = { * users: [ * { * id: 1, * name: 'Ed Spencer', * phoneNumber: '555 1234' * }, * { * id: 2, * name: 'Abe Elias', * phoneNumber: '666 1234' * } * ] * }; * * // note how we set the 'root' in the reader to match the data structure above * var store = Ext.create('Ext.data.Store', { * autoLoad: true, * model: 'User', * data: data, * proxy: { * type: 'memory', * reader: { * type: 'json', * rootProperty: 'users' * } * } * }); */Ext.define('Ext.data.proxy.Memory', { extend: 'Ext.data.proxy.Client', alias: 'proxy.memory', alternateClassName: 'Ext.data.MemoryProxy', isMemoryProxy: true, config: { /** * @cfg {Boolean} [enablePaging=false] * Configure as `true` to enable this MemoryProxy to honour a read operation's `start` * and `limit` options. * * When `true`, read operations will be able to read *pages* of records from the data object. */ enablePaging: null, /** * @cfg {Object} data * Optional data to pass to configured Reader. */ data: { $value: null, // Because of destructive association reading, we always need to clone incoming data // to protect externally owned data objects from mutation merge: function(newValue, currentValue, target, mixinClass) { return newValue ? Ext.clone(newValue) : newValue; } }, /** * @cfg {Boolean} [clearOnRead=false] * By default MemoryProxy data is persistent, and subsequent reads will read the * same data. If this is not required, configure the proxy using `clearOnRead: true`. */ clearOnRead: null }, /** * @private * Fake processing function to commit the records, set the current operation * to successful and call the callback if provided. This function is shared * by the create, update and destroy methods to perform the bare minimum * processing required for the proxy to register a result from the action. */ finishOperation: function(operation) { var recs = operation.getRecords(), len = recs.length, i; for (i = 0; i < len; i++) { // Because Memory proxy is synchronous, the commit must call store#afterErase recs[i].dropped = !!operation.isDestroyOperation; recs[i].commit(); } operation.setSuccessful(true); }, /** * Currently this is a hard-coded method that simply commits any records and sets the operation * to successful, then calls the callback function, if provided. It is essentially mocking * a server call in memory, but since there is no real back end in this case there's not much * else to do. This method can be easily overridden to implement more complex logic if needed. * @param {Ext.data.operation.Operation} operation The Operation to perform * @method */ create: function(operation) { this.finishOperation(operation); }, /** * Currently this is a hard-coded method that simply commits any records and sets the operation * to successful, then calls the callback function, if provided. It is essentially mocking * a server call in memory, but since there is no real back end in this case there's not much * else to do. This method can be easily overridden to implement more complex logic if needed. * @param {Ext.data.operation.Operation} operation The Operation to perform * @method */ update: function(operation) { this.finishOperation(operation); }, /** * Currently this is a hard-coded method that simply commits any records and sets the operation * to successful, then calls the callback function, if provided. It is essentially mocking * a server call in memory, but since there is no real back end in this case there's not much * else to do. This method can be easily overridden to implement more complex logic if needed. * @param {Ext.data.operation.Operation} operation The Operation to perform * @method */ erase: function(operation) { this.finishOperation(operation); }, /** * Reads data from the configured {@link #data} object. Uses the Proxy's {@link #reader}, * if present. * @param {Ext.data.operation.Operation} operation The read Operation */ read: function(operation) { var me = this, reader = me.getReader(), resultSet = reader.read(me.getData(), { recordCreator: reader.defaultRecordCreatorFromServer }), records = resultSet.getRecords(), sorters = operation.getSorters(), groupers = operation.getGroupers(), grouper = operation.getGrouper(), filters = operation.getFilters(), start = operation.getStart(), limit = operation.getLimit(), meta; // Apply filters, sorters, and start/limit options if (operation.process(resultSet, null, null, false) !== false) { // If we are configured to read the data one time only, clear our data if (operation.success && me.getClearOnRead()) { this.setData(null); } // Filter the resulting array of records if (filters && filters.length) { // Total will be updated by setting records /* eslint-disable-next-line max-len */ resultSet.setRecords(records = Ext.Array.filter(records, Ext.util.Filter.createFilterFn(filters))); resultSet.setTotal(records.length); } // Remotely, grouper just mean top priority sorters if (groupers && groupers.length) { // Must concat so as not to mutate passed sorters array which could be // the items property of the sorters collection sorters = sorters ? groupers.concat(sorters) : groupers; } else if (grouper) { // Must concat so as not to mutate passed sorters array which could be the items // property of the sorters collection sorters = sorters ? sorters.concat(grouper) : sorters; } // Sort by the specified grouper and sorters if (sorters && sorters.length) { /* eslint-disable-next-line max-len */ resultSet.setRecords(records = Ext.Array.sort(records, Ext.util.Sortable.createComparator(sorters))); } // Reader reads the whole passed data object. // If successful and we were given a start and limit, slice the result. if (me.getEnablePaging() && start !== undefined && limit !== undefined) { // Attempt to read past end of memory dataset - convert to failure if (start >= resultSet.getTotal()) { resultSet.setConfig({ success: false, records: [], total: 0 }); } // Range is valid, slice it up. else { resultSet.setRecords(Ext.Array.slice(records, start, start + limit)); } } operation.setCompleted(); // If a JsonReader detected metadata, process it now. // This will fire the 'metachange' event which the Store processes to fire its own // 'metachange' meta = resultSet.getMetadata(); if (meta) { me.onMetaChange(meta); } } }, clear: Ext.emptyFn});