<commit_before>// TODO: use bundle's copy of jquery, other things?

function with_id(obj, id) {
  return _.extend({ id: id }, obj);
}

function get_prop(obj, path) {
  path = path.split('.');

  _.each(path, function(prop) {
    if (!(prop in obj)) {
      throw new Error('property ' + prop + ' not found');
    }

    obj = obj[prop];
  });

  return obj;
}

function MeteorStore(options) {
  this.collection = options.collection;
  this.annotationPath = options.annotationPath;
  this.createDocument = options.createDocument;

  this.handle = null;

  this.firesMutationEvents = true;
}

MeteorStore.prototype.configure = function(configs) {
  this.core = configs.core;
}

MeteorStore.prototype.create = function(annotation) {
  var dfd = $.Deferred();

  this.collection.insert(this.createDocument(annotation), function(error, id) {
    if (error) {
      dfd.reject('Failed to create object: ' + error);
    } else {
      dfd.resolve(with_id(annotation, id));
    }
  });

  return dfd.promise();
}

MeteorStore.prototype.update = function(annotation) {
  var dfd = $.Deferred();

  var set_obj = {};
  set_obj[this.annotationPath] = _.omit(annotation, 'id');

  this.collection.update(annotation.id, { $set: set_obj }, function(error, rows) {
    if (error) {
      dfd.reject('Failed to update singular object: ' + error);
    } else {
      dfd.resolve(annotation);
    }
  });

  return dfd.promise();
}

MeteorStore.prototype.delete = function(annotation) {
  var dfd = $.Deferred();

  this.collection.remove(annotation.id, function(error) {
    if (error) {
      dfd.reject('Failed to delete object: ' + error);
    } else {
      dfd.resolve(annotation);
    }
  });

  return dfd.promise();
}

MeteorStore.prototype.query = function(queryObj) {
  var self = this;

  var field_spec = {};
  field_spec[this.annotationPath] = 1;

  this._stop();

  function trigger(event, doc) {
    self.core.trigger(event, doc);
  }

  this.handle = this.collection.find(queryObj, {
    fields: field_spec,
    transform: function(doc) {
      return with_id(get_prop(doc, self.annotationPath), doc._id);
    }
  }).observe({
    added: function(doc) {
      trigger('annotationCreated', doc);
    },
    changed: function(new_doc, old_doc) {
      trigger('annotationUpdated', new_doc);
    },
    removed: function(old) {
      trigger('annotationDeleted', old);
    }
  });

  // TODO: send initial results to the deferred instead of using annotationCreated?
  var dfd = $.Deferred();
  dfd.resolve([], {});<commit_msg>Pass initial documents to the query deferred.<commit_after>// TODO: use bundle's copy of jquery, other things?

function with_id(obj, id) {
  return _.extend({ id: id }, obj);
}

function get_prop(obj, path) {
  path = path.split('.');

  _.each(path, function(prop) {
    if (!(prop in obj)) {
      throw new Error('property ' + prop + ' not found');
    }

    obj = obj[prop];
  });

  return obj;
}

function MeteorStore(options) {
  this.collection = options.collection;
  this.annotationPath = options.annotationPath;
  this.createDocument = options.createDocument;

  this.handle = null;

  this.firesMutationEvents = true;
}

MeteorStore.prototype.configure = function(configs) {
  this.core = configs.core;
}

MeteorStore.prototype.create = function(annotation) {
  var dfd = $.Deferred();

  this.collection.insert(this.createDocument(annotation), function(error, id) {
    if (error) {
      dfd.reject('Failed to create object: ' + error);
    } else {
      dfd.resolve(with_id(annotation, id));
    }
  });

  return dfd.promise();
}

MeteorStore.prototype.update = function(annotation) {
  var dfd = $.Deferred();

  var set_obj = {};
  set_obj[this.annotationPath] = _.omit(annotation, 'id');

  this.collection.update(annotation.id, { $set: set_obj }, function(error, rows) {
    if (error) {
      dfd.reject('Failed to update singular object: ' + error);
    } else {
      dfd.resolve(annotation);
    }
  });

  return dfd.promise();
}

MeteorStore.prototype.delete = function(annotation) {
  var dfd = $.Deferred();

  this.collection.remove(annotation.id, function(error) {
    if (error) {
      dfd.reject('Failed to delete object: ' + error);
    } else {
      dfd.resolve(annotation);
    }
  });

  return dfd.promise();
}

MeteorStore.prototype.query = function(queryObj) {
  var self = this;

  var field_spec = {};
  field_spec[this.annotationPath] = 1;

  this._stop();

  function trigger(event, doc) {
    self.core.trigger(event, doc);
  }

  var handlingInitialDocuments = true;
  var initialDocuments = [];
  this.handle = this.collection.find(queryObj, {
    fields: field_spec,
    transform: function(doc) {
      return with_id(get_prop(doc, self.annotationPath), doc._id);
    }
  }).observe({
    added: function(doc) {
      if (handlingInitialDocuments) {
        initialDocuments.push(doc);
      } else {
        trigger('annotationCreated', doc);
      }
    },
    changed: function(new_doc, old_doc) {
      trigger('annotationUpdated', new_doc);
    },
    removed: function(old) {
      trigger('annotationDeleted', old);
    }
  });
  handlingInitialDocuments = false;

  var dfd = $.Deferred();
  dfd.resolve(initialDocuments, {});
{'fraction_non_alphanumeric': 0.14878095603762717, 'fraction_numerical': 0.0003839508542906508, 'mean_word_length': 3.341666666666667, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, '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': '3290331', 'n_tokens_mistral': 1724, 'n_tokens_neox': 1663, 'n_words': 352}