<commit_before>import Orbit from 'orbit/core';
import Document from 'orbit/document';
import Transformable from 'orbit/transformable';
import Requestable from 'orbit/requestable';

var MemoryStore = function(options) {
  Orbit.assert('MemoryStore requires Orbit.Promise to be defined', Orbit.Promise);

  options = options || {};

  this.idField = Orbit.idField;
  this._cache = new Document();
  this.configure(options.schema);

  Transformable.extend(this);
  Requestable.extend(this, ['find', 'add', 'update', 'patch', 'remove']);
};

MemoryStore.prototype = {
  constructor: MemoryStore,

  configure: function(schema) {
    this.schema = schema;
    this._cache.add(['deleted'], {});
    schema.models.forEach(function(model) {
      this._cache.add([model], {});
      this._cache.add(['deleted', model], {});
    }, this);
  },

  retrieve: function(path) {
    try {
      return this._cache.retrieve(path);
    } catch(e) {
      return null;
    }
  },

  length: function(path) {
    return Object.keys(this.retrieve(path)).length;
  },

  isDeleted: function(path) {
    // TODO - normalize paths
    if (typeof path === 'string') {
      path = path.split('/');
    }
    return this.retrieve(['deleted'].concat(path));
  },

  /////////////////////////////////////////////////////////////////////////////
  // Transformable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _transform: function(operation, transaction) {
    var _this = this;
    return new Orbit.Promise(function(resolve, reject) {
      if (transaction) {
        transaction.inverse.push(_this._cache.transform(operation, true));
      } else {
        _this._cache.transform(operation);

        // Track deleted records
        if (operation.op === 'remove') {
          // TODO - normalize paths
          var path = operation.path;
          if (typeof path === 'string') {
            path = path.split('/');
          }
          if (path.length === 2) {
            _this._cache.transform({op: 'add', path: ['deleted'].concat(path), value: true});
          }
        }
      }
      resolve(_this.retrieve(operation.path));
    });
  },

  /////////////////////////////////////////////////////////////////////////////
  // Requestable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _find: function(type, id) {
    var _this = this;

    return new Orbit.Promise(function(resolve, reject) {
      if (id === undefined || typeof id === 'object') {
        resolve(_this._filter.call(_this, type, id));
      } else {
        var record = _this.retrieve([type, id]);
        if (record && !record.deleted) {
          resolve(record);
        } else {
          reject(new Orbit.NotFoundException(type, id));
        }
      }
    });
  },

  _add: function(type, data) {
    var id = this._generateId(),
        path = [type, id],
        _this = this;

    data[this.idField] = id;
    Orbit.incrementVersion(data);

    return this.transform({op: 'add', path: path, value: data});
  },

  _update: function(type, data) {
    var id = data[this.idField],
        path = [type, id],
        _this = this;

    Orbit.incrementVersion(data);

    return this.transform({op: 'replace', path: path, value: data});
  },

  _patch: function(type, id, property, value) {
    var _this = this,
        path;

    if (typeof id === 'object') id = id[this.idField];
    path = [type, id].concat(this._cache.deserializePath(property));

    return this.transform({op: 'replace', path: path, value: value});
  },

  _remove: function(type, data) {
    var id = (typeof data === 'object' ? data[this.idField] : data),
        path = [type, id];

    return this.transform({op: 'remove', path: path});
  },

  /////////////////////////////////////////////////////////////////////////////
  // Internals
  /////////////////////////////////////////////////////////////////////////////

  _filter: function(type, query) {
    var all = [],
        dataForType,
        i,
        prop,
        match,
        record;

    dataForType = this.retrieve([type]);

    for (i in dataForType) {
      if (dataForType.hasOwnProperty(i)) {
        record = dataForType[i];
        if (query === undefined) {
          match = true;
        } else {
          match = false;
          for (prop in query) {
            if (record[prop] === query[prop]) {
              match = true;
            } else {
              match = false;
              break;
            }
          }
        }
        if (match && !record.deleted) {
          all.push(record);
        }
      }
    }
    return all;
  },

  _generateId: function() {
    return Orbit.generateId();
  }
};

export default MemoryStore;<commit_msg>Fixed versioning of records in `_transform`<commit_after>import Orbit from 'orbit/core';
import Document from 'orbit/document';
import Transformable from 'orbit/transformable';
import Requestable from 'orbit/requestable';

var MemoryStore = function(options) {
  Orbit.assert('MemoryStore requires Orbit.Promise to be defined', Orbit.Promise);

  options = options || {};

  this.idField = Orbit.idField;
  this._cache = new Document();
  this.configure(options.schema);

  Transformable.extend(this);
  Requestable.extend(this, ['find', 'add', 'update', 'patch', 'remove']);
};

MemoryStore.prototype = {
  constructor: MemoryStore,

  configure: function(schema) {
    this.schema = schema;
    this._cache.add(['deleted'], {});
    schema.models.forEach(function(model) {
      this._cache.add([model], {});
      this._cache.add(['deleted', model], {});
    }, this);
  },

  retrieve: function(path) {
    try {
      return this._cache.retrieve(path);
    } catch(e) {
      return null;
    }
  },

  length: function(path) {
    return Object.keys(this.retrieve(path)).length;
  },

  isDeleted: function(path) {
    // TODO - normalize paths
    if (typeof path === 'string') {
      path = path.split('/');
    }
    return this.retrieve(['deleted'].concat(path));
  },

  /////////////////////////////////////////////////////////////////////////////
  // Transformable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _transform: function(operation, transaction) {
    var _this = this;
    return new Orbit.Promise(function(resolve, reject) {
      var ops = [operation];

      // TODO - normalize paths
      var path = operation.path;
      if (typeof path === 'string') {
        path = path.split('/');
      }

      // Track deleted records
      if (operation.op === 'remove' && path.length === 2) {
        ops.push({op: 'add', path: ['deleted'].concat(path), value: true});

      // Version other records
      } else if (path.length > 1) {
        ops.push({op: 'add', path: path.slice(0,2).concat([Orbit.versionField]), value: Orbit.newVersion()});
      }

      for (var i = 0; i < ops.length; i++) {
        if (transaction) {
          transaction.inverse.push(_this._cache.transform(ops[i], true));
        } else {
          _this._cache.transform(ops[i]);
        }
      }

      resolve(_this.retrieve(operation.path));
    });
  },

  /////////////////////////////////////////////////////////////////////////////
  // Requestable interface implementation
  /////////////////////////////////////////////////////////////////////////////

  _find: function(type, id) {
    var _this = this;

    return new Orbit.Promise(function(resolve, reject) {
      if (id === undefined || typeof id === 'object') {
        resolve(_this._filter.call(_this, type, id));
      } else {
        var record = _this.retrieve([type, id]);
        if (record && !record.deleted) {
          resolve(record);
        } else {
          reject(new Orbit.NotFoundException(type, id));
        }
      }
    });
  },

  _add: function(type, data) {
    var id = this._generateId(),
        path = [type, id],
        _this = this;

    data[this.idField] = id;

    return this.transform({op: 'add', path: path, value: data});
  },

  _update: function(type, data) {
    var id = data[this.idField],
        path = [type, id],
        _this = this;

    return this.transform({op: 'replace', path: path, value: data});
  },

  _patch: function(type, id, property, value) {
    var _this = this,
        path;

    if (typeof id === 'object') id = id[this.idField];
    path = [type, id].concat(this._cache.deserializePath(property));

    return this.transform({op: 'replace', path: path, value: value});
  },

  _remove: function(type, data) {
    var id = (typeof data === 'object' ? data[this.idField] : data),
        path = [type, id];

    return this.transform({op: 'remove', path: path});
  },

  /////////////////////////////////////////////////////////////////////////////
  // Internals
  /////////////////////////////////////////////////////////////////////////////

  _filter: function(type, query) {
    var all = [],
        dataForType,
        i,
        prop,
        match,
        record;

    dataForType = this.retrieve([type]);

    for (i in dataForType) {
      if (dataForType.hasOwnProperty(i)) {
        record = dataForType[i];
        if (query === undefined) {
          match = true;
        } else {
          match = false;
          for (prop in query) {
            if (record[prop] === query[prop]) {
              match = true;
            } else {
              match = false;
              break;
            }
          }
        }
        if (match && !record.deleted) {
          all.push(record);
        }
      }
    }
    return all;
  },

  _generateId: function() {
    return Orbit.generateId();
  }
};

export default MemoryStore;
{'fraction_non_alphanumeric': 0.2337848932676519, 'fraction_numerical': 0.0006157635467980296, 'mean_word_length': 1.7076965823839956, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 4, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5094246', 'n_tokens_mistral': 2743, 'n_tokens_neox': 2676, 'n_words': 622}