/lib/collections/base-collection.js

https://bitbucket.org/madebybottle/bottlecap · JavaScript · 143 lines · 96 code · 23 blank · 24 comment · 21 complexity · a99e0b2eb4dbde6717ad1f49affd5ba3 MD5 · raw file

  1. module.exports = function(options) {
  2. // ## BaseCollection
  3. // -----------------
  4. // The BaseCollection is the base Collection for storing instances of models
  5. // for Bottlecap. It is the same as a normal Backbone.Collection, but with
  6. // a few alterations:
  7. //
  8. // - It keeps a reference to the event bus upon construction
  9. // - It can reply to DataStore API requests on that event bus, if a
  10. // namespace option is passed to it.
  11. // ### Dependencies
  12. // ----------------
  13. var Backbone = options.Backbone;
  14. var _ = options._;
  15. var FilterCollection = options.FilterCollection;
  16. // ### BaseCollection
  17. // ------------------
  18. var BaseCollection = Backbone.Collection.extend({
  19. // The DataStore API events
  20. dataStoreAPI: [
  21. 'all', 'find', 'where', 'filter', 'build'
  22. ],
  23. // Creates a BaseCollection and returns it. Accepts `models`, and
  24. // `options` parameters. The `options` parameter should contain an
  25. // instance of the application event bus. If you want this BaseCollection
  26. // to be able to respond to DataStore API requests on the event bus, you
  27. // should also pass a `namespace` property on the `options` object.
  28. constructor: function(models, options) {
  29. Backbone.Collection.apply(this, arguments);
  30. models = models || [];
  31. options = options || {};
  32. this._vent = options.vent;
  33. if (!this.namespace) {
  34. this.namespace = options.namespace;
  35. }
  36. if (this.namespace) {
  37. var locals = _.map(this.dataStoreAPI, function(name) {
  38. return '_' + name;
  39. });
  40. _.bindAll(this, locals);
  41. this._setupDSBindings(this.namespace, this.dataStoreAPI);
  42. }
  43. return this;
  44. },
  45. // ### DataStore API functions
  46. _subcollection: function(options) {
  47. var col = new FilterCollection({
  48. filter: options.filter,
  49. parent: this
  50. });
  51. return col;
  52. },
  53. _build: function(attrs, options, cb) {
  54. var args = Array.prototype.slice.call(arguments);
  55. if (args.length === 1) {
  56. cb = args[0];
  57. attrs = {};
  58. options = {};
  59. } else if (args.length === 2) {
  60. attrs = args[0];
  61. options = {};
  62. cb = args[1];
  63. }
  64. var model = new this.model(attrs, options);
  65. return cb (null, model);
  66. },
  67. _all: function(cb) {
  68. var filter = function(model) { return true; };
  69. var all = this._subcollection({filter: filter});
  70. return cb(null, all);
  71. },
  72. _find: function(attrs, cb) {
  73. this._where(attrs, function(err, data) {
  74. if (err) { return cb(err); }
  75. if (data.length < 1) {
  76. err = new Error('DSNotFoundError');
  77. return cb(err);
  78. }
  79. var model = data.at(0);
  80. return cb(null, model);
  81. });
  82. },
  83. _where: function(attrs, cb) {
  84. var filter = function(model) {
  85. for (var key in attrs) {
  86. var modelValue = model.get(key);
  87. var value = attrs[key];
  88. if ((value instanceof Array) && (modelValue instanceof Array)) {
  89. if (value !== modelValue) { return false; }
  90. } else if (value instanceof Array) {
  91. if (!_.contains(value, modelValue)) { return false; }
  92. } else if (modelValue instanceof Array) {
  93. if (!_.contains(modelValue, value)) { return false; }
  94. } else {
  95. if (modelValue !== value) { return false; }
  96. }
  97. }
  98. return true;
  99. };
  100. var col = this._subcollection({filter: filter});
  101. return cb(null, col);
  102. },
  103. _filter: function(filter, cb) {
  104. var col = this._subcollection({filter: filter});
  105. return cb(null, col);
  106. },
  107. // Binds DataStore API message names to functions on this instance. For
  108. // example, ds:contacts:all -> this._all
  109. _setupDSBindings: function(namespace, dsEvents) {
  110. _.each(dsEvents, function(name) {
  111. var messageName = 'ds:' + namespace + ':' + name;
  112. var ourFunc = this['_' + name];
  113. this._vent.handle(messageName, ourFunc);
  114. }, this);
  115. }
  116. });
  117. // ### Exports
  118. // -----------
  119. return BaseCollection;
  120. };