bookshelf: Missing columns after save()

I have a table with created_at and updated_at timestamps. The values for those columns are automatically generated by the database server. I don’t want to generate those values in code, I want them generated by db server to maintain accuracy across all app servers.

I create a new model like this:

var instance = new Model({
    'name': 'Joe'
});
instance.save().then(function() {
    console.log(instance.toJSON());
});

The result of instance.toJSON() is missing both created_at and updated_at columns, even though they do exist in the database. Pretty much every ORM platform I recall working with has automatically pulled those values for me.

If I submit a PR, can we get a fix merged in?

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Comments: 39 (21 by maintainers)

Commits related to this issue

Most upvoted comments

@ricka You are right it wasn’t working with both insert and update so I ended up with this workaround :

this.on('saving', (model, attrs, options) => {
  if (options.method === 'insert') {
    // workaround (cf. https://github.com/tgriesser/bookshelf/issues/507#issuecomment-99634467)
    Object.defineProperty(options.query._single, 'returning', {
      get() { return '*'; },
      set() { return '*'; },
      configurable: true,
      enumerable: true,
      writeable: true,
    });
  } else {
    options.query.returning('*');
  }
});
this.on('saved', (model, attrs, options) => {
  if (options.method === 'insert') {
    // workaround (cf. https://github.com/tgriesser/bookshelf/issues/507#issuecomment-99634467)
    model.set(model.parse(model.id));
  } else {
    const id = model.get(model.idAttribute);
    if (id) {
      const findById = find(propEq('id', id));
      const attr = findById(attrs);
      if (attr) model.set(model.parse(attr));
    }
  }
});

It’s kind of a compilation of all the answers which are using the returning * postgres feature 😃

I got my use case working with the following code. Note: the previous examples are not taking transactions into account. .save may be called with {transacting: trx} option and it should be passed to the .refresh() call.

var bookshelf = Bookshelf(knex);

// Needed because postgres autogenerates created_at
// timestamp. Otherwise it wouldn't be returned on model.save().
var save = bookshelf.Model.prototype.save;
bookshelf.Model.prototype.save = function(_, fetchOpts) {
    return save.apply(this, arguments).then(function(model) {
        // fetchOpts contains transaction info
        return model ? model.refresh(fetchOpts) : model;
    });
};

Is this still open or a final solution had been implemented and commited? Thanks

Hey @tgriesser going to +1 this issue,

Perhaps adding a method saveAndFetch() might be a nice addition to the api namespace… If you are open to this more than willing to PR up this sucker.

For postgres, it would be nice not to do the additional fetch and just use returning('*')

This would also work:

var save = bookshelf.Model.prototype.save;
bookshelf.Model.prototype.save = function() {
   return save.apply(this, arguments).then(function(model) {
     var id = model.id;
     return model ? model.clear().set('id', id).fetch() : model;
   })
};

But I agree, this is a bug, I’ll patch this to work as expected in the next minor version.

So are you just looking to do an immediate fetch after save?