Added support for composite keys as the `idAttribute` #1558

Closed
wants to merge 2 commits into
from

Projects

None yet

6 participants

@caseywebdev
Collaborator

I like to create Backbone models for my join tables, but I don't want to throw an unnecessary id field in the table when a composite key is ideal. This commit makes it possible to set idAttribute to an array of attribute names. See the tests for examples. Please let me know if there is a case where this breaks, but all tests passing so far.

@jashkenas
Owner

Sounds fine -- but you shouldn't have to patch Backbone to support this. If you want to find a model by a unique combination of userId and taskId -- just use find. The "composite keys" in this patch would break URL compatibility, the .get api, and so on.

@jashkenas jashkenas closed this Aug 17, 2012
@caseywebdev
Collaborator

There's no way to guarantee uniqueness in a Collection of composite key join models without manually iterating through after each .add since they aren't indexed by a single id. Could you elaborate on how this breaks URL compatibility? And I don't think .get will ever be used on a composite key collection, but id generation is crucial for uniqueness.

@braddunbar
Collaborator

You could use parse instead.

var Model = Backbone.Model.extend({
  parse: function(resp) {
    resp.id = resp.x + resp.y;
    return resp;
  }
});
@knowtheory
Collaborator

Backbone assumes a RESTful API structure by default, and that resources all have a single unique key. Urls for models are built up by grabbing the collection url or the model's urlRoot and appending that model's id.

@caseywebdev
Collaborator

@braddunbar I like that. Obviously it will break if rest.x or resp.y changes, but then again, they'll probably never change.

resources all have a single unique key

I thought about adding an id field to the join table for just this reason, but I just can't justify that as an id on a join table would increase too rapidly.

I'll go with a parse-like solution for now and see how it works out. Thanks!

@jashkenas
Owner

Another way to go, if you just want to validate uniqueness, is to, ahem, use validate.

@caseywebdev
Collaborator

In case anyone stumbles across this, I ended up using

class app.Model extends Backbone.Model
  initialize: ->
    @_previousId = @id = @_generateId()

  change: ->
    @_previousId = @id
    @id = @_generateId()
    super arguments...

  _generateId: ->
    return get @idAttribute unless @compositeKey
    vals = []
    for index in @compositeKey
      return undefined unless (val = @get index)?
      vals.push val
    vals.join '_'

class app.Model.Collection extends Backbone.Collection
  _onModelEvent: (event, model, collection, options) ->
    if model and event is 'change' and model.id isnt model._previousId
      delete @_byId[model._previousId];
      @_byId[model.id] = model if model.id?
    super arguments...

class app.Appointment extends app.Model
  compositeKey: ['doctorId', 'patientId']

class app.Appointment.Collection extends app.Model.Collection
  model: app.Appointment

I haven't tested it yet but in theory this solves my problem.

@vespakoen

I am also looking for this functionality since I have different types of models in the same collection.

What about allowing a callback for the idAttribute property, like the url and urlRoot do at this moment, then the ID could be created on initialization / update etc?

Please shoot some holes in this idea =)

@caseywebdev
Collaborator

I've created a plugin for this at backbone-composite-keys if you wanna check that out. You simply provide an array of attributes as the idAttribute and internally the id is maintained as 'id-id' or 'id-id-id' etc...

@madtyn
madtyn commented Mar 20, 2014

Hello, a Javascript beginner here.

I'm working in a project in which we're looking for using composite-ids and we're interested in using this backbone-composite-keys js library.

Could you please provide some small example on how to declare a Backbone Model and how to create it.

I know there is a test, but is in made in Coffee language and I don't understan it very well. I would be very grateful if someone could write in JS a minimal example of a simple object declaration and an instantiation sentence with 'new'.

Thanks very much in advance.

@caseywebdev
Collaborator

@madtyn Unfortunately I haven't kept that library up to date, but you're in luck! Support for composite keys actually just landed in master via generateId. Check out #2985 for more info.

@madtyn
madtyn commented Mar 20, 2014

I'm checking. Thank you very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment