Improvement ideas fro Ember-Data


#1

I have worked with Ember-Data for almost a year for now. I’m using some third party API that I can’t change, so I have written a big custom adapter and lot of workarounds. I wanted to discuss few improvement ideas, before putting them to gitHub. Ideas are little bit of related to each other.

  1. Singleton model. Sometimes there is a model that always has exactly one instance (at least on client side). Most used example of this is user session login=getSession (usually you only have exactly one active session). There are other cases too like give me some daily sales total number, give me total number of signed up users etc. Simple workaround is always to assign id 1 to this model in adapter. It would be better if there would be an option to define singleton model without having ID at all.

  2. Add query to findById I have cases where I need to get one object with additional parameters. One use case is singleton object described in point 1 (sending username and password for getSession), but sometimes also for other queries. For one example I have getReport commend to get HTML report by report_id and I can pass some params there. Current workaround is doing findQuery and getting first object from the array, but it creates some extra work. I think it’s common use case and should be in Ember-Data. So findById(type, id) should be findById(type, id, query) or separate function findByIdAndQuery(type, id, query).

  3. Defining findQuery params in a model and serialization for findQuery parameters There should be a way to define findQuery parameters in a model. Lets say I want to find some objects in a date range, then I want to define startDate and endDate. Object attribute is „date“, but „startDate“ and „endDate“ should be query parameters. For primitive data types it’s not a big problem, but complex types like Date, BigNumber etc need to go through serialization and transform mechanism. Currently I’m putting query parameters to the model together with model attributes, and improved findQuery code so all query parameters go through serialization process (currently this is not a case).

Ember-Data is a great library and makes things so much easier, hopefully it gets even better:)


#2

I like 1 & 2, although I’m not quite sure I understand 3.

I also think store.find(type, id, queryParams) should work.


#3

We’ve been building Singleton models fairly easy with minimum changes.

  1. Reopen the class of the model you want to be a singleton and add isSingleton: true
  2. Change the buildURL code from the adapter to check on the model isSingleton. If false, call super, if true, make sure the url does not pluralize
  3. Override the find function of your store and supper undefined id and the the on isSingleton, if true, then change the id to singleton.

#4

Hey @MichaelVdheeren can you provide an example of that?


#5

Yes, I can. See below for Ember Data beta 16.1 example.

Your store:

import DS from 'ember-data';

export default DS.Store.extend({
  find: function(type) {
    if (this.modelFor(type).isSingleton) {
      return this._super(type, 'singleton');
    }

    return this._super.apply(this, arguments);
  }

Your adapter:

import Em from 'ember';
import DS from 'ember-data';

var decamelize = Em.String.decamelize,
underscore     = Em.String.underscore,
get            = Em.get;

export default DS.ActiveModelAdapter.extend({
  // Coalesce find requests
  coalesceFindRequests: true,
  buildURL: function(type) {
    var url           = [],
    host          = get(this, 'host'),
    prefix        = this.urlPrefix(),
    container     = this.container, // jshint ignore:line
    normalizedKey = this.container._registry.normalize('model:' + type),
    model         = this.container.lookupFactory(normalizedKey);

    if (typeof model.urlPrefix === "string" || model.urlPrefix instanceof String) {
      url.push(model.urlPrefix);
    }

    if (!!model.isSingleton) {
      var decamelized = decamelize(type),
      underscored = underscore(decamelized);

      url.push(underscored);

      if (prefix) { url.unshift(prefix); }

      url = url.join('/');
      if (!host && url) { url = '/' + url; }

      return url;
    } else {
      return this._super.apply(this, arguments);
    }
  },
});

A model (hosted at url: /api/session/singleton on your server):

import DS from 'ember-data';
import Em from 'ember';

var attr      = DS.attr,
    belongsTo = DS.belongsTo;

var Model = DS.Model.extend({
  
});

Model.reopenClass({
  isSingleton: true,
});

export default Model;